@@ -48,24 +48,33 @@ public class BuilderRule implements Rule<JDefinedClass, JDefinedClass> {
48
48
public JDefinedClass apply (String nodeName , JsonNode node , JsonNode parent , JDefinedClass instanceClass , Schema currentSchema ) {
49
49
50
50
// Create the inner class for the builder
51
+ JDefinedClass concreteBuilderClass ;
51
52
JDefinedClass builderClass ;
52
53
53
54
try {
54
- String builderName = ruleFactory .getNameHelper ().getBuilderClassName (instanceClass );
55
- builderClass = instanceClass ._class (JMod .PUBLIC + JMod .STATIC , builderName );
55
+
56
+ String concreteBuilderClassName = ruleFactory .getNameHelper ().getBuilderClassName (instanceClass );
57
+ String builderClassName = ruleFactory .getNameHelper ().getBaseBuilderClassName (instanceClass );
58
+
59
+ builderClass = instanceClass ._class (JMod .ABSTRACT + JMod .PUBLIC + JMod .STATIC , builderClassName );
60
+
61
+ concreteBuilderClass = instanceClass ._class (JMod .PUBLIC + JMod .STATIC , concreteBuilderClassName );
62
+ concreteBuilderClass ._extends (builderClass .narrow (instanceClass ));
63
+
56
64
} catch (JClassAlreadyExistsException e ) {
57
65
return e .getExistingClass ();
58
66
}
59
67
60
- // Determine which builder (if any) this builder should inherit from
68
+ // Determine which base builder (if any) this builder should inherit from
61
69
JClass parentBuilderClass = null ;
62
70
JClass parentClass = instanceClass ._extends ();
63
71
if (!(parentClass .isPrimitive () || reflectionHelper .isFinal (parentClass ) || Objects .equals (parentClass .fullName (), "java.lang.Object" ))) {
64
- parentBuilderClass = reflectionHelper .getBuilderClass (parentClass );
72
+ parentBuilderClass = reflectionHelper .getBaseBuilderClass (parentClass );
65
73
}
66
74
67
- // Determine the generic type 'T' that the builder will create instances of
68
- JTypeVar instanceType = builderClass .generify ("T" , instanceClass );
75
+ // Determine the generic type name and that the builder will create instances of
76
+ String builderTypeParameterName = ruleFactory .getNameHelper ().getBuilderTypeParameterName (instanceClass );
77
+ JTypeVar instanceType = builderClass .generify (builderTypeParameterName , instanceClass );
69
78
70
79
// For new builders we need to create an instance variable and 'build' method
71
80
// for inheriting builders we'll receive these from the superType
@@ -83,31 +92,50 @@ public JDefinedClass apply(String nodeName, JsonNode node, JsonNode parent, JDef
83
92
body .assign (JExpr ._this ().ref (instanceField ), JExpr ._null ());
84
93
body ._return (result );
85
94
86
- // Create the noargs builder constructor
87
- generateNoArgsBuilderConstructor (instanceClass , builderClass );
95
+ // Create the noargs builder constructors
96
+ generateNoArgsBuilderConstructors (instanceClass , builderClass , concreteBuilderClass );
88
97
} else {
89
98
// Declare the inheritance
90
- builderClass ._extends (parentBuilderClass );
91
-
99
+ builderClass ._extends (parentBuilderClass . narrow ( parentBuilderClass . owner (). ref ( builderTypeParameterName )) );
100
+
92
101
JMethod buildMethod = builderClass .method (JMod .PUBLIC , instanceType , "build" );
93
102
buildMethod .annotate (Override .class );
94
103
95
104
JBlock body = buildMethod .body ();
96
- body ._return (JExpr .cast ( instanceType , JExpr . _super ().invoke ("build" ) ));
105
+ body ._return (JExpr ._super ().invoke ("build" ));
97
106
98
- // Create the noargs builder constructor
99
- generateNoArgsBuilderConstructor (instanceClass , builderClass );
107
+ // Create the noargs builder constructors
108
+ generateNoArgsBuilderConstructors (instanceClass , builderClass , concreteBuilderClass );
100
109
}
101
110
102
111
return builderClass ;
103
112
}
104
113
105
- private void generateNoArgsBuilderConstructor (JDefinedClass instanceClass , JDefinedClass builderClass ) {
106
- JMethod noargsConstructor = builderClass .constructor (JMod .PUBLIC );
107
- JAnnotationUse warningSuppression = noargsConstructor .annotate (SuppressWarnings .class );
114
+ private void generateNoArgsBuilderConstructors (JDefinedClass instanceClass , JDefinedClass baseBuilderClass , JDefinedClass builderClass ) {
115
+
116
+ generateNoArgsBaseBuilderConstructor (instanceClass , baseBuilderClass , builderClass );
117
+ generateNoArgsBuilderConstructor (instanceClass , baseBuilderClass , builderClass );
118
+ }
119
+
120
+ private void generateNoArgsBuilderConstructor (JDefinedClass instanceClass , JDefinedClass baseBuilderClass , JDefinedClass builderClass ) {
121
+
122
+ // Add the constructor to builder.
123
+ JMethod noArgsConstructor = builderClass .constructor (JMod .PUBLIC );
124
+ JBlock constructorBlock = noArgsConstructor .body ();
125
+
126
+ // Determine if we need to invoke the super() method for our parent builder
127
+ if (!(baseBuilderClass .isPrimitive () || reflectionHelper .isFinal (baseBuilderClass ) || Objects .equals (baseBuilderClass .fullName (), "java.lang.Object" ))) {
128
+ constructorBlock .invoke ("super" );
129
+ }
130
+ }
131
+
132
+ private void generateNoArgsBaseBuilderConstructor (JDefinedClass instanceClass , JDefinedClass builderClass , JDefinedClass concreteBuilderClass ) {
133
+
134
+ JMethod noArgsConstructor = builderClass .constructor (JMod .PUBLIC );
135
+ JAnnotationUse warningSuppression = noArgsConstructor .annotate (SuppressWarnings .class );
108
136
warningSuppression .param ("value" , "unchecked" );
109
137
110
- JBlock constructorBlock = noargsConstructor .body ();
138
+ JBlock constructorBlock = noArgsConstructor .body ();
111
139
112
140
JFieldVar instanceField = reflectionHelper .searchClassAndSuperClassesForField ("instance" , builderClass );
113
141
@@ -120,9 +148,8 @@ private void generateNoArgsBuilderConstructor(JDefinedClass instanceClass, JDefi
120
148
// Only initialize the instance if the object being constructed is actually this class
121
149
// if it's a subtype then ignore the instance initialization since the subclass will initialize it
122
150
constructorBlock .directStatement ("// Skip initialization when called from subclass" );
123
- JInvocation comparison = JExpr ._this ().invoke ("getClass" ).invoke ("equals" ).arg (JExpr .dotclass (builderClass ));
151
+ JInvocation comparison = JExpr ._this ().invoke ("getClass" ).invoke ("equals" ).arg (JExpr .dotclass (concreteBuilderClass ));
124
152
JConditional ifNotSubclass = constructorBlock ._if (comparison );
125
153
ifNotSubclass ._then ().assign (JExpr ._this ().ref (instanceField ), JExpr .cast (instanceField .type (), JExpr ._new (instanceClass )));
126
154
}
127
-
128
155
}
0 commit comments