View Javadoc
1   /*
2    * SPDX-License-Identifier: Apache-2.0
3    * See LICENSE file for details.
4    *
5    * Copyright 2012-2026 hazendaz
6    *
7    * Portions of initial baseline code (getter/setter test) by Rob Dawson (CodeBox)
8    */
9   package com.codebox.bean;
10  
11  import com.codebox.enums.CheckClear;
12  import com.codebox.enums.CheckConstructor;
13  import com.codebox.enums.CheckEquals;
14  import com.codebox.enums.CheckSerialize;
15  import com.codebox.enums.LoadData;
16  import com.codebox.enums.SkipStrictSerialize;
17  import com.codebox.instance.ConstructorInstance;
18  
19  import java.util.Arrays;
20  
21  /**
22   * Fluent configuration object returned by {@link JavaBeanTester#builder(Class)}.
23   *
24   * <p>
25   * Configure optional checks by chaining methods such as {@link #checkEquals()}, {@link #checkSerializable()},
26   * {@link #loadData()}, or {@link #skip(String...)}, then finish with a terminal method such as {@link #test()},
27   * {@link #testInstance(Object)}, {@link #testEquals(Object, Object)}, {@link #testObjectMethods()}, or
28   * {@link #testPrivateConstructor()}.
29   *
30   * @param <T>
31   *            the type under test
32   * @param <E>
33   *            the extension type used for equality-related checks
34   */
35  public class JavaBeanTesterBuilder<T, E> {
36  
37      /** The worker. */
38      private final JavaBeanTesterWorker<T, E> worker;
39  
40      /**
41       * Instantiates a new java bean tester builder.
42       *
43       * @param clazz
44       *            the clazz
45       */
46      JavaBeanTesterBuilder(final Class<T> clazz) {
47          this.worker = new JavaBeanTesterWorker<>(clazz);
48      }
49  
50      /**
51       * Instantiates a new java bean tester builder.
52       *
53       * @param clazz
54       *            the clazz
55       * @param extension
56       *            the extension
57       */
58      JavaBeanTesterBuilder(final Class<T> clazz, final Class<E> extension) {
59          this.worker = new JavaBeanTesterWorker<>(clazz, extension);
60      }
61  
62      /**
63       * Enables {@code clear()} verification.
64       *
65       * @return this builder
66       */
67      public JavaBeanTesterBuilder<T, E> checkClear() {
68          return this.checkClear(true);
69      }
70  
71      /**
72       * Toggles {@code clear()} verification.
73       *
74       * @param value
75       *            {@code true} to enable the check, {@code false} to disable it
76       *
77       * @return this builder
78       */
79      public JavaBeanTesterBuilder<T, E> checkClear(final boolean value) {
80          this.worker.setCheckClear(value ? CheckClear.ON : CheckClear.OFF);
81          return this;
82      }
83  
84      /**
85       * Enables public-constructor verification.
86       *
87       * @return this builder
88       */
89      public JavaBeanTesterBuilder<T, E> checkConstructor() {
90          return this.checkConstructor(true);
91      }
92  
93      /**
94       * Toggles public-constructor verification.
95       *
96       * @param value
97       *            {@code true} to enable the check, {@code false} to disable it
98       *
99       * @return this builder
100      */
101     public JavaBeanTesterBuilder<T, E> checkConstructor(final boolean value) {
102         this.worker.setCheckConstructor(value ? CheckConstructor.ON : CheckConstructor.OFF);
103         return this;
104     }
105 
106     /**
107      * Enables {@code equals}, {@code hashCode}, {@code toString}, and {@code canEqual} verification.
108      *
109      * @return this builder
110      */
111     public JavaBeanTesterBuilder<T, E> checkEquals() {
112         return this.checkEquals(true);
113     }
114 
115     /**
116      * Toggles {@code equals}, {@code hashCode}, {@code toString}, and {@code canEqual} verification.
117      *
118      * @param value
119      *            {@code true} to enable the check, {@code false} to disable it
120      *
121      * @return this builder
122      */
123     public JavaBeanTesterBuilder<T, E> checkEquals(final boolean value) {
124         this.worker.setCheckEquals(value ? CheckEquals.ON : CheckEquals.OFF);
125         return this;
126     }
127 
128     /**
129      * Requires the type under test to be serializable and validates a serialization round-trip.
130      *
131      * @return this builder
132      */
133     public JavaBeanTesterBuilder<T, E> checkSerializable() {
134         return this.checkSerializable(true);
135     }
136 
137     /**
138      * Toggles strict serializable validation.
139      *
140      * @param value
141      *            {@code true} to require serialization support, {@code false} to skip the strict requirement
142      *
143      * @return this builder
144      */
145     public JavaBeanTesterBuilder<T, E> checkSerializable(final boolean value) {
146         this.worker.setCheckSerializable(value ? CheckSerialize.ON : CheckSerialize.OFF);
147         return this;
148     }
149 
150     /**
151      * Enables recursive sample-data generation for supported property types.
152      *
153      * @return this builder
154      */
155     public JavaBeanTesterBuilder<T, E> loadData() {
156         return this.loadData(true);
157     }
158 
159     /**
160      * Toggles recursive sample-data generation for supported property types.
161      *
162      * @param value
163      *            {@code true} to enable generated data, {@code false} to disable it
164      *
165      * @return this builder
166      */
167     public JavaBeanTesterBuilder<T, E> loadData(final boolean value) {
168         this.worker.setLoadData(value ? LoadData.ON : LoadData.OFF);
169         return this;
170     }
171 
172     /**
173      * Skip Strict Serializable is intended to relax strict check on serializable objects. For complex objects, strict
174      * checking will result in issues with equals check. Testing has shown this to be generally not a normal use case of
175      * javabean tester as it is normally used with POJOs only. In such a case, caller will get an error and if there is
176      * not actually a code problem they should turn this skip on.
177      *
178      * @return the java bean tester builder
179      */
180     public JavaBeanTesterBuilder<T, E> skipStrictSerializable() {
181         this.worker.setSkipStrictSerializable(SkipStrictSerialize.ON);
182         return this;
183     }
184 
185     /**
186      * Skips the supplied bean properties during getter/setter validation.
187      *
188      * @param propertyNames
189      *            the bean property names to exclude
190      *
191      * @return this builder
192      */
193     public JavaBeanTesterBuilder<T, E> skip(final String... propertyNames) {
194         if (propertyNames != null) {
195             this.worker.getSkipThese().addAll(Arrays.asList(propertyNames));
196         }
197         return this;
198     }
199 
200     /**
201      * Runs the configured bean validation flow.
202      */
203     public void test() {
204         this.worker.test();
205     }
206 
207     /**
208      * Verifies that a private constructor can be exercised.
209      */
210     public void testPrivateConstructor() {
211         ConstructorInstance.inaccessible(this.worker.getClazz());
212     }
213 
214     /**
215      * Runs only the object-method checks for the configured class.
216      */
217     public void testObjectMethods() {
218         this.worker.equalsHashCodeToStringSymmetricTest();
219     }
220 
221     /**
222      * Runs getter/setter checks against the supplied instance.
223      *
224      * @param instance
225      *            the instance to populate and verify
226      */
227     public void testInstance(final T instance) {
228         this.worker.getterSetterTests(instance);
229     }
230 
231     /**
232      * Compares two prepared instances using the configured equality options.
233      *
234      * @param instance
235      *            the instance under test
236      * @param expected
237      *            the expected comparison instance
238      */
239     public void testEquals(final T instance, final T expected) {
240         this.worker.equalsTests(instance, expected);
241     }
242 
243 }