4848
4949import javax .lang .model .element .Modifier ;
5050import java .util .ArrayList ;
51+ import java .util .Arrays ;
5152import java .util .Collection ;
5253import java .util .Collections ;
5354import java .util .HashSet ;
@@ -100,34 +101,23 @@ public void visitClass(ClassElement element, VisitorContext context) {
100101 return ;
101102 }
102103 try {
103- String simpleName = element .getSimpleName () + "Builder" ;
104- String builderClassName = element .getPackageName () + "." + simpleName ;
105-
106- ClassTypeDef builderType = ClassTypeDef .of (builderClassName );
107-
108- ClassDef .ClassDefBuilder builder = ClassDef .builder (builderClassName )
109- .addModifiers (Modifier .PUBLIC , Modifier .FINAL );
110- addAnnotations (builder , element .getAnnotation (Builder .class ));
111-
112104 List <PropertyElement > properties = element .getBeanProperties ();
113- for (PropertyElement beanProperty : properties ) {
114- createModifyPropertyMethod (builder , beanProperty , ExpressionDef ::returning );
115- }
116-
117- builder .addMethod (MethodDef .constructor ().build ());
118- if (!properties .isEmpty ()) {
119- builder .addMethod (createAllPropertiesConstructor (properties ));
120- }
121-
122- builder .addMethod (createBuilderMethod (builderType ));
123- builder .addMethod (createBuildMethod (element ));
105+ @ NonNull ParameterElement [] constructorElement = element .getPrimaryConstructor ()
106+ .filter (c -> !c .isPrivate ())
107+ .or (element ::getDefaultConstructor )
108+ .map (MethodElement ::getParameters ).orElse (ParameterElement .ZERO_PARAMETER_ELEMENTS );
109+ List <ParameterElement > constructorParameters = Arrays .asList (constructorElement );
110+ AnnotationValue <Builder > builderAnnotationValue = element .getAnnotation (Builder .class );
111+ ClassTypeDef elementType = ClassTypeDef .of (element );
112+
113+ ClassDefBuilder builder = createBuilder (element .getPackageName (), elementType , builderAnnotationValue , properties , constructorParameters );
114+ ClassDef builderDef = builder .build ();
124115
125116 SourceGenerator sourceGenerator = SourceGenerators .findByLanguage (context .getLanguage ()).orElse (null );
126117 if (sourceGenerator == null ) {
127118 return ;
128119 }
129120
130- ClassDef builderDef = builder .build ();
131121 processed .add (element .getName ());
132122 sourceGenerator .write (builderDef , context , element );
133123 } catch (ProcessingException e ) {
@@ -145,6 +135,72 @@ public void visitClass(ClassElement element, VisitorContext context) {
145135 }
146136 }
147137
138+ /**
139+ * Create a builder for the given arguments.
140+ * @param packageName The package name
141+ * @param elementType The element type
142+ * @param builderAnnotationValue The builder annotation value.
143+ * @param properties The properties
144+ * @param constructorParameters The constructor parameters
145+ * @return A class definition builder for the builder
146+ */
147+ static @ NonNull ClassDefBuilder createBuilder (
148+ String packageName ,
149+ @ NonNull ClassTypeDef elementType ,
150+ @ Nullable AnnotationValue <Builder > builderAnnotationValue ,
151+ @ NonNull List <PropertyElement > properties ,
152+ @ NonNull List <ParameterElement > constructorParameters ) {
153+ Function <BuilderGenerator .BuildContext , StatementDef > returnSelf = (context ) -> context .aThis ().returning ();
154+ return createBuilder (packageName , elementType , builderAnnotationValue , properties , constructorParameters , returnSelf );
155+ }
156+
157+ /**
158+ * Create a builder for the given arguments.
159+ *
160+ * @param packageName The package name
161+ * @param elementType The element type
162+ * @param builderAnnotationValue The builder annotation value.
163+ * @param properties The properties
164+ * @param constructorParameters The constructor parameters
165+ * @param buildReturnStatement The return statement to use for building.
166+ * @return A class definition builder for the builder
167+ */
168+ static ClassDefBuilder createBuilder (
169+ String packageName ,
170+ ClassTypeDef elementType ,
171+ AnnotationValue <Builder > builderAnnotationValue ,
172+ List <PropertyElement > properties ,
173+ List <ParameterElement > constructorParameters ,
174+ Function <BuilderGenerator .BuildContext , StatementDef > buildReturnStatement ) {
175+ String simpleName = elementType .getSimpleName () + "Builder" ;
176+ String builderClassName = packageName + "." + simpleName ;
177+ ClassTypeDef builderType = ClassTypeDef .of (builderClassName );
178+
179+ ClassDefBuilder builder = ClassDef .builder (builderClassName )
180+ .addModifiers (Modifier .PUBLIC , Modifier .FINAL );
181+ if (builderAnnotationValue != null ) {
182+ addAnnotations (builder , builderAnnotationValue );
183+ }
184+
185+ for (PropertyElement beanProperty : properties ) {
186+ createModifyPropertyMethod (builder , beanProperty , buildReturnStatement );
187+ }
188+
189+ builder .addMethod (MethodDef .constructor ().build ());
190+ if (!properties .isEmpty ()) {
191+ builder .addMethod (createAllPropertiesConstructor (properties ));
192+ }
193+
194+ builder .addMethod (createBuilderMethod (builderType ));
195+
196+ builder .addMethod (createBuildMethod (
197+ elementType ,
198+ properties ,
199+ constructorParameters )
200+ );
201+ return builder ;
202+ }
203+
148204 static void addAnnotations (ClassDefBuilder builder , AnnotationValue <?> annotation ) {
149205 Optional <AnnotationClassValue []> annotatedWith = annotation .getConvertibleValues ()
150206 .get (BUILDER_ANNOTATED_WITH_MEMBER , AnnotationClassValue [].class );
@@ -212,7 +268,7 @@ private static StatementDef mapToArrayListStatement(VariableDef.Field propertyFi
212268 );
213269 }
214270
215- private MethodDef createBuilderMethod (ClassTypeDef builderType ) {
271+ private static MethodDef createBuilderMethod (ClassTypeDef builderType ) {
216272 return MethodDef .builder ("builder" )
217273 .addModifiers (Modifier .PUBLIC , Modifier .STATIC )
218274 .returns (builderType )
@@ -222,7 +278,7 @@ private MethodDef createBuilderMethod(ClassTypeDef builderType) {
222278
223279 static void createModifyPropertyMethod (ClassDef .ClassDefBuilder classDefBuilder ,
224280 PropertyElement beanProperty ,
225- Function <VariableDef . This , StatementDef > returningExpressionProvider ) {
281+ Function <BuilderGenerator . BuildContext , StatementDef > returningExpressionProvider ) {
226282 if (beanProperty .hasAnnotation (Singular .class )) {
227283 createSingularPropertyMethods (classDefBuilder , beanProperty , returningExpressionProvider );
228284 } else {
@@ -232,7 +288,7 @@ static void createModifyPropertyMethod(ClassDef.ClassDefBuilder classDefBuilder,
232288
233289 private static void createDefaultModifyPropertyMethod (ClassDef .ClassDefBuilder classDefBuilder ,
234290 PropertyElement beanProperty ,
235- Function <VariableDef . This , StatementDef > returningExpressionProvider ) {
291+ Function <BuilderGenerator . BuildContext , StatementDef > returningExpressionProvider ) {
236292 TypeDef propertyTypeDef = TypeDef .of (beanProperty .getType ());
237293 FieldDef field = createField (beanProperty , propertyTypeDef );
238294 classDefBuilder .addField (field );
@@ -242,7 +298,7 @@ private static void createDefaultModifyPropertyMethod(ClassDef.ClassDefBuilder c
242298 .addParameter (propertyName , propertyTypeDef )
243299 .build ((self , parameterDefs ) -> StatementDef .multi (
244300 self .field (field ).assign (parameterDefs .get (0 )),
245- returningExpressionProvider .apply (self )
301+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
246302 )));
247303 }
248304
@@ -266,7 +322,7 @@ private static FieldDef createField(PropertyElement beanProperty, TypeDef type)
266322
267323 private static void createSingularPropertyMethods (ClassDef .ClassDefBuilder classBuilder ,
268324 PropertyElement beanProperty ,
269- Function <VariableDef . This , StatementDef > returningExpressionProvider ) {
325+ Function <BuilderGenerator . BuildContext , StatementDef > returningExpressionProvider ) {
270326 String propertyName = beanProperty .getSimpleName ();
271327 String singularName = beanProperty .stringValue (Singular .class ).orElse (null );
272328 if (singularName == null ) {
@@ -293,7 +349,7 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class
293349 self .field (field ).assign (ClassTypeDef .of (ArrayList .class ).instantiate ())
294350 ),
295351 self .field (field ).invoke ("addAll" , TypeDef .primitive (boolean .class ), parameterDefs .get (0 )),
296- returningExpressionProvider .apply (self )
352+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
297353 )));
298354 classBuilder .addMethod (MethodDef .builder (singularName )
299355 .addModifiers (Modifier .PUBLIC )
@@ -303,15 +359,15 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class
303359 self .field (field ).assign (ClassTypeDef .of (ArrayList .class ).instantiate ())
304360 ),
305361 self .field (field ).invoke ("add" , TypeDef .of (boolean .class ), parameterDefs .get (0 )),
306- returningExpressionProvider .apply (self )
362+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
307363 )));
308364 classBuilder .addMethod (MethodDef .builder ("clear" + StringUtils .capitalize (propertyName ))
309365 .addModifiers (Modifier .PUBLIC )
310366 .build ((self , parameterDefs ) -> StatementDef .multi (
311367 self .field (field ).isNonNull ().doIf (
312368 self .field (field ).invoke ("clear" , TypeDef .VOID )
313369 ),
314- returningExpressionProvider .apply (self )
370+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
315371 )));
316372 } else if (beanProperty .getType ().isAssignable (Map .class )) {
317373 TypeDef keyType = beanProperty .getType ().getFirstTypeArgument ().<TypeDef >map (ClassTypeDef ::of ).orElse (TypeDef .OBJECT );
@@ -341,7 +397,7 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class
341397 TypeDef .primitive (boolean .class ),
342398 parameterDefs .get (0 ).invoke ("entrySet" , ClassTypeDef .of (Set .class ))
343399 ),
344- returningExpressionProvider .apply (self )
400+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
345401 )));
346402 classBuilder .addMethod (MethodDef .builder (singularName )
347403 .addModifiers (Modifier .PUBLIC )
@@ -361,47 +417,39 @@ private static void createSingularPropertyMethods(ClassDef.ClassDefBuilder class
361417 parameterDefs .get (1 )
362418 )
363419 ),
364- returningExpressionProvider .apply (self )
420+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
365421 )));
366422 classBuilder .addMethod (MethodDef .builder ("clear" + StringUtils .capitalize (propertyName ))
367423 .addModifiers (Modifier .PUBLIC )
368424 .build ((self , parameterDefs ) -> StatementDef .multi (
369425 self .field (field ).isNonNull ().doIf (
370426 self .field (field ).invoke ("clear" , TypeDef .VOID )
371427 ),
372- returningExpressionProvider .apply (self )
428+ returningExpressionProvider .apply (new BuilderGenerator . BuildContext ( self , field ) )
373429 )));
374430 } else {
375431 throw new IllegalStateException ("Unsupported singular collection type [" + beanProperty .getType ().getName () + "] for property: " + beanProperty .getName ());
376432 }
377433 }
378434
379- static MethodDef createBuildMethod (ClassElement producedType ) {
435+ static MethodDef createBuildMethod (ClassTypeDef buildType , List < PropertyElement > properties , List < ParameterElement > constructorParameters ) {
380436 return MethodDef .builder ("build" )
381437 .addModifiers (Modifier .PUBLIC )
382438 .build ((self , parameterDefs ) -> {
383- MethodElement constructorElement = producedType .getPrimaryConstructor ()
384- .filter (c -> !c .isPrivate ())
385- .or (producedType ::getDefaultConstructor )
386- .orElse (null );
387-
388- List <PropertyElement > beanProperties = new ArrayList <>(producedType .getBeanProperties ());
439+ List <PropertyElement > beanProperties = new ArrayList <>(properties );
389440 List <ExpressionDef > values = new ArrayList <>();
390- if (constructorElement != null ) {
391- for (ParameterElement parameter : constructorElement .getParameters ()) {
392- PropertyElement propertyElement = beanProperties .stream ().filter (p -> p .getName ().equals (parameter .getName ())).findFirst ().orElse (null );
393- if (propertyElement != null ) {
394- beanProperties .remove (propertyElement );
395- }
396- // We need to convert it for the correct type in Kotlin
397- TypeDef fieldType = TypeDef .of (parameter .getType ()).makeNullable ();
398- VariableDef .Field field = self .field (parameter .getName (), fieldType );
399- values .add (
400- valueExpression (propertyElement , field ).cast (TypeDef .of (parameter .getType ()))
401- );
441+ for (ParameterElement parameter : constructorParameters ) {
442+ PropertyElement propertyElement = beanProperties .stream ().filter (p -> p .getName ().equals (parameter .getName ())).findFirst ().orElse (null );
443+ if (propertyElement != null ) {
444+ beanProperties .remove (propertyElement );
402445 }
446+ // We need to convert it for the correct type in Kotlin
447+ TypeDef fieldType = TypeDef .of (parameter .getType ()).makeNullable ();
448+ VariableDef .Field field = self .field (parameter .getName (), fieldType );
449+ values .add (
450+ valueExpression (propertyElement , field ).cast (TypeDef .of (parameter .getType ()))
451+ );
403452 }
404- ClassTypeDef buildType = ClassTypeDef .of (producedType );
405453 if (beanProperties .isEmpty ()) {
406454 return buildType .instantiate (values ).returning ();
407455 }
0 commit comments