44import javax .lang .model .type .TypeMirror ;
55import javax .lang .model .util .ElementFilter ;
66
7+ import static java .util .stream .Collectors .toSet ;
8+
79import java .util .*;
810import java .util .function .Supplier ;
911import java .util .stream .Collectors ;
@@ -41,11 +43,8 @@ final class TypeReader {
4143 private boolean nonAccessibleField ;
4244
4345 private final Map <String , Element > mixInFields ;
44-
4546 private final String typePropertyKey ;
46-
4747 private final Map <String , Integer > frequencyMap = new HashMap <>();
48-
4948 private final List <MethodProperty > methodProperties = new ArrayList <>();
5049
5150 private boolean optional ;
@@ -139,10 +138,9 @@ void read(TypeElement type) {
139138 for (var param : constructor .getParams ()) {
140139 var name = param .name ();
141140 var element = param .element ();
142- var matchingField =
143- localFields .stream ()
144- .filter (f -> f .propertyName ().equals (name ) || f .fieldName ().equals (name ))
145- .findFirst ();
141+ var matchingField = localFields .stream ()
142+ .filter (f -> f .propertyName ().equals (name ) || f .fieldName ().equals (name ))
143+ .findFirst ();
146144 matchingField .ifPresentOrElse (f -> f .readParam (element ), () -> readField (element , localFields ));
147145 }
148146 }
@@ -161,7 +159,6 @@ void read(TypeElement type) {
161159 } else {
162160 commonField .addSubType (currentSubType );
163161 }
164-
165162 if (commonField == null && currentSubType != null ) {
166163 localField .setSubTypeField ();
167164 }
@@ -172,22 +169,19 @@ void read(TypeElement type) {
172169 private void readField (Element element , List <FieldReader > localFields ) {
173170 final Element mixInField = mixInFields .get (element .getSimpleName ().toString ());
174171 if (mixInField != null && APContext .types ().isSameType (mixInField .asType (), element .asType ())) {
175-
176172 var mixinModifiers = new HashSet <>(mixInField .getModifiers ());
177173 var modifiers = new HashSet <>(mixInField .getModifiers ());
178174
179175 Arrays .stream (Modifier .values ())
180- .filter (m -> m != Modifier .PRIVATE || m != Modifier .PROTECTED || m != Modifier .PUBLIC )
181- .forEach (
182- m -> {
183- modifiers .remove (m );
184- mixinModifiers .remove (m );
185- });
176+ .filter (m -> m != Modifier .PRIVATE || m != Modifier .PROTECTED || m != Modifier .PUBLIC )
177+ .forEach (m -> {
178+ modifiers .remove (m );
179+ mixinModifiers .remove (m );
180+ });
186181
187182 if (!modifiers .equals (mixinModifiers )) {
188183 APContext .logError (mixInField , "mixIn fields must have the same modifiers as the target class" );
189184 }
190-
191185 element = mixInField ;
192186 }
193187 if (element .asType ().toString ().contains ("java.util.Optional" )) {
@@ -304,13 +298,17 @@ private void matchFieldsToSetterOrConstructor() {
304298 }
305299
306300 private void matchFieldToSetter (FieldReader field ) {
307- if (!matchFieldToSetter2 (field , false )
301+ if (hasNoSetter (field )) {
302+ logError ("Non public field " + baseType + " " + field .fieldName () + " with no matching setter or constructor?" );
303+ }
304+ }
305+
306+ private boolean hasNoSetter (FieldReader field ) {
307+ return !matchFieldToSetter2 (field , false )
308308 && !matchFieldToSetter2 (field , true )
309309 && !matchFieldToSetterByParam (field )
310310 && !field .isPublicField ()
311- && !field .isSubTypeField ()) {
312- logError ("Non public field " + baseType + " " + field .fieldName () + " with no matching setter or constructor?" );
313- }
311+ && !field .isSubTypeField ();
314312 }
315313
316314 private boolean matchFieldToSetterByParam (FieldReader field ) {
@@ -458,7 +456,26 @@ private MethodReader determineConstructor() {
458456 // fallback to the single public constructor
459457 return allPublic .get (0 );
460458 }
461- // find the largest constructor
459+
460+ // find the right constructor
461+ var constructorFields = allFields .stream ()
462+ .filter (FieldReader ::includeFromJson )
463+ .filter (this ::hasNoSetter )
464+ .map (f -> f .element ().asType ().toString ())
465+ .map (Util ::trimAnnotations )
466+ .collect (toSet ());
467+
468+ return allPublic .stream ()
469+ .filter (c -> c .getParams ().size () == constructorFields .size ())
470+ .filter (c -> c .getParams ().stream ()
471+ .map (p -> p .element ().asType ().toString ())
472+ .map (Util ::trimAnnotations )
473+ .allMatch (constructorFields ::contains ))
474+ .findFirst ()
475+ .orElseGet (this ::largest );
476+ }
477+
478+ private MethodReader largest () {
462479 int argCount = 0 ;
463480 MethodReader largestConstructor = null ;
464481 for (MethodReader ctor : publicConstructors ) {
0 commit comments