View Javadoc
1   /*
2    * JavaBean Tester (https://github.com/hazendaz/javabean-tester)
3    *
4    * Copyright 2012-2021 Hazendaz.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of The Apache Software License,
8    * Version 2.0 which accompanies this distribution, and is available at
9    * http://www.apache.org/licenses/LICENSE-2.0.txt
10   *
11   * Contributors:
12   *     CodeBox (Rob Dawson).
13   *     Hazendaz (Jeremy Landis).
14   */
15  package com.codebox.instance;
16  
17  import com.codebox.bean.ValueBuilder;
18  import com.codebox.enums.LoadData;
19  import com.codebox.enums.LoadType;
20  
21  import java.lang.reflect.Constructor;
22  import java.lang.reflect.InvocationTargetException;
23  import java.util.Arrays;
24  
25  import org.junit.jupiter.api.Assertions;
26  
27  /**
28   * The Class Instance.
29   *
30   * @param <T>
31   *            the element type
32   */
33  public class ClassInstance<T> {
34  
35      /**
36       * New instance. This will get the first available constructor to run the test on. This allows for instances where
37       * there is intentionally not a no-arg constructor.
38       *
39       * @param clazz
40       *            the class
41       *
42       * @return the t
43       */
44      @SuppressWarnings("unchecked")
45      public final T newInstance(final Class<T> clazz) {
46          // Try no-arg constructor first
47          for (final Constructor<?> constructor : clazz.getConstructors()) {
48              // Skip deprecated constructors
49              if (constructor.isAnnotationPresent(Deprecated.class)) {
50                  continue;
51              }
52  
53              // Find available no-arg constructor and return it
54              if (constructor.getParameterCount() == 0) {
55                  try {
56                      return (T) constructor.newInstance((Object[]) null);
57                  } catch (final InstantiationException | IllegalAccessException | InvocationTargetException e) {
58                      Assertions.fail(String.format(
59                              "An exception was thrown while testing the class (new instance) '%s' with '%s': '%s'",
60                              constructor.getName(), Arrays.toString((Object[]) null), e.toString()));
61                  }
62              }
63          }
64  
65          // Try any constructor
66          for (final Constructor<?> constructor : clazz.getConstructors()) {
67  
68              // Skip deprecated constructors
69              if (constructor.isAnnotationPresent(Deprecated.class)) {
70                  continue;
71              }
72  
73              final Class<?>[] types = constructor.getParameterTypes();
74  
75              final Object[] values = new Object[constructor.getParameterTypes().length];
76  
77              // Load Data
78              for (int i = 0; i < values.length; i++) {
79                  values[i] = this.buildValue(types[i], LoadType.STANDARD_DATA);
80              }
81  
82              try {
83                  return (T) constructor.newInstance(values);
84              } catch (final InstantiationException | IllegalAccessException | InvocationTargetException e) {
85                  Assertions.fail(String.format(
86                          "An exception was thrown while testing the class (new instance) '%s' with '%s': '%s'",
87                          constructor.getName(), Arrays.toString(values), e.toString()));
88              }
89          }
90          return null;
91      }
92  
93      /**
94       * Builds the value.
95       *
96       * @param <R>
97       *            the generic type
98       * @param returnType
99       *            the return type
100      * @param loadType
101      *            the load type
102      *
103      * @return the object
104      */
105     public <R> Object buildValue(final Class<R> returnType, final LoadType loadType) {
106         final ValueBuilder valueBuilder = new ValueBuilder();
107         valueBuilder.setLoadData(LoadData.ON);
108         return valueBuilder.buildValue(returnType, loadType);
109     }
110 
111 }