3636
3737import java .util .ArrayDeque ;
3838import java .util .ArrayList ;
39+ import java .util .Collections ;
3940import java .util .Deque ;
4041import java .util .HashSet ;
4142import java .util .LinkedHashMap ;
5051import javax .lang .model .element .Element ;
5152import javax .lang .model .element .ElementKind ;
5253import javax .lang .model .element .ExecutableElement ;
54+ import javax .lang .model .element .Modifier ;
5355import javax .lang .model .element .TypeElement ;
5456import javax .lang .model .type .TypeMirror ;
5557import javax .tools .Diagnostic ;
@@ -104,6 +106,19 @@ public HierarchyScannerResult scan(TypeElement root) {
104106 HierarchyScannerResult nodeResult = scanSingleNode (node );
105107
106108 for (PropertyInfo p : nodeResult .getProperties ()) {
109+ // we need to generate getter/setter if not yet implemented
110+ if (node .getKind () == ElementKind .INTERFACE
111+ || p .getGetterElement () == null
112+ || p .getGetterElement ().getModifiers ().contains (Modifier .ABSTRACT )) {
113+ p .setGenerateGetter (true );
114+ }
115+ if (p .isGenerateGetter ()
116+ || node .getKind () == ElementKind .INTERFACE
117+ || p .getSetterElement () == null
118+ || p .getSetterElement ().getModifiers ().contains (Modifier .ABSTRACT )) {
119+ p .setGenerateSetter (true );
120+ }
121+
107122 PropertyInfo before = mergedProperties .get (p .getName ());
108123 if (before != null ) {
109124 // Back-fill blank metadata from the parent before the child wins.
@@ -120,6 +135,7 @@ public HierarchyScannerResult scan(TypeElement root) {
120135 p .getAnnotation ().hide ()));
121136 }
122137 }
138+
123139 mergedProperties .put (p .getName (), p );
124140 }
125141
@@ -190,13 +206,11 @@ HierarchyScannerResult scanSingleNode(TypeElement element) {
190206 * Tries the {@code PropertyKeys} reflection strategy first, then the {@code @Property} annotation strategy.
191207 */
192208 private List <PropertyInfo > scanProperties (TypeElement element ) {
209+ List <PropertyInfo > result = new ArrayList <>();
193210 String className = element .getQualifiedName ().toString ();
194211 try {
195212 Class <?> clazz = Class .forName (className , false , processorClassLoader );
196- List <PropertyInfo > reflectionResult = scanPropertyKeysViaReflection (clazz , element );
197- if (reflectionResult != null ) {
198- return reflectionResult ;
199- }
213+ result .addAll (scanPropertyKeysViaReflection (clazz , element ));
200214 }
201215 catch (ClassNotFoundException ignored ) {
202216 // in-round source — fall through to annotation scan
@@ -205,7 +219,7 @@ private List<PropertyInfo> scanProperties(TypeElement element) {
205219 messager .printMessage (Diagnostic .Kind .WARNING ,
206220 "Reflection failed for " + className + ": " + e .getMessage ());
207221 }
208- return scanPropertyAnnotations (element );
222+ return scanPropertyAnnotations (element , result );
209223 }
210224
211225 /**
@@ -254,7 +268,7 @@ private List<PropertyInfo> scanPropertyKeysViaReflection(Class<?> clazz, TypeEle
254268
255269 return result ;
256270 }
257- return null ;
271+ return Collections . emptyList () ;
258272 }
259273
260274 /**
@@ -305,9 +319,7 @@ private ExecutableElement findGetterElement(TypeElement element, String property
305319 /**
306320 * Scans {@code @Property}-annotated getters via the Element API.
307321 */
308- private List <PropertyInfo > scanPropertyAnnotations (TypeElement element ) {
309- List <PropertyInfo > result = new ArrayList <>();
310-
322+ private List <PropertyInfo > scanPropertyAnnotations (TypeElement element , List <PropertyInfo > result ) {
311323 for (Element enclosed : element .getEnclosedElements ()) {
312324 if (enclosed .getKind () != ElementKind .METHOD ) {
313325 continue ;
@@ -327,10 +339,18 @@ private List<PropertyInfo> scanPropertyAnnotations(TypeElement element) {
327339
328340 String propName = extractPropertyName (methodName );
329341 ExecutableElement setter = findSetterInElement (element , propName , method .getReturnType ());
330- result .add (new PropertyInfo (propName ,
331- new PropertyLiteral (annotation .description (), annotation .required (), annotation .defaultValue (),
332- annotation .implicitDefaultValue (), annotation .callSuper (), null , annotation .hide ()),
333- method , setter , method .getReturnType ().toString ()));
342+ PropertyInfo propertyInfo = result .stream ().filter (p -> p .getName ().equals (propName )).findFirst ().orElse (null );
343+ if (propertyInfo == null ) {
344+ result .add (new PropertyInfo (propName ,
345+ new PropertyLiteral (annotation .description (), annotation .required (), annotation .defaultValue (),
346+ annotation .implicitDefaultValue (), annotation .callSuper (), null , annotation .hide ()),
347+ method , setter , method .getReturnType ().toString ()));
348+ }
349+ else {
350+ propertyInfo .setGetterElement (method );
351+ propertyInfo .setSetterElement (setter );
352+ propertyInfo .setTypeName (method .getReturnType ().toString ());
353+ }
334354 }
335355
336356 return result ;
0 commit comments