1717import java .util .function .Predicate ;
1818import java .util .stream .Stream ;
1919
20- import javax .lang .model .element .AnnotationMirror ;
21- import javax .lang .model .element .ExecutableElement ;
22- import javax .lang .model .element .Modifier ;
20+ import javax .lang .model .element .*;
2321
2422public enum ParameterGenerator {
2523 ContextParam ("getAttribute" , "io.jooby.annotation.ContextParam" , "jakarta.ws.rs.core.Context" ) {
@@ -116,32 +114,37 @@ public String toSourceCode(
116114 TypeDefinition type ,
117115 String name ,
118116 boolean nullable ) {
117+ List <Element > converters = new ArrayList <>();
119118 var typeNames = findAnnotationValue (annotation , AnnotationSupport .VALUE );
120119 var typeName = typeNames .isEmpty () ? null : typeNames .get (0 );
121120 var router = route .getRouter ();
122121 var targetType = router .getTargetType ();
123- var converter =
124- typeName == null
125- ? targetType
126- : route
127- .getContext ()
128- .getProcessingEnvironment ()
129- .getElementUtils ()
130- .getTypeElement (typeName );
122+ var env = route .getContext ().getProcessingEnvironment ();
123+ if (typeName != null ) {
124+ converters .add (env .getElementUtils ().getTypeElement (typeName ));
125+ } else {
126+ // Fallback bean class first
127+ converters .add (env .getTypeUtils ().asElement (type .getRawType ()));
128+ // Fallback controller class later
129+ converters .add (targetType );
130+ }
131131 var fns = findAnnotationValue (annotation , "fn" ::equals );
132132 var fn = fns .isEmpty () ? null : fns .get (0 );
133133 Predicate <ExecutableElement > contextAsParameter =
134134 it ->
135135 it .getParameters ().size () == 1
136136 && it .getParameters ().get (0 ).asType ().toString ().equals ("io.jooby.Context" );
137- Predicate <ExecutableElement > matchesReturnType =
138- it ->
139- new TypeDefinition (
140- route .getContext ().getProcessingEnvironment ().getTypeUtils (),
141- it .getReturnType ())
142- .getRawType ()
143- .equals (type .getRawType ());
144- var filter = contextAsParameter .and (matchesReturnType );
137+ Predicate <ExecutableElement > matchesType =
138+ it -> {
139+ var returnType =
140+ new TypeDefinition (
141+ route .getContext ().getProcessingEnvironment ().getTypeUtils (),
142+ it .getReturnType ())
143+ .getRawType ();
144+ return returnType .equals (type .getRawType ())
145+ || (it .getSimpleName ().toString ().equals ("<init>" ));
146+ };
147+ var filter = contextAsParameter .and (matchesType );
145148 String methodErrorName ;
146149 if (fn != null ) {
147150 Predicate <ExecutableElement > matchesName = it -> it .getSimpleName ().toString ().equals (fn );
@@ -152,7 +155,8 @@ public String toSourceCode(
152155 }
153156 // find function by type
154157 ExecutableElement mapping =
155- converter .getEnclosedElements ().stream ()
158+ converters .stream ()
159+ .flatMap (it -> it .getEnclosedElements ().stream ())
156160 .filter (ExecutableElement .class ::isInstance )
157161 .map (ExecutableElement .class ::cast )
158162 // filter by Context
@@ -161,21 +165,23 @@ public String toSourceCode(
161165 .orElseThrow (
162166 () ->
163167 new IllegalArgumentException (
164- "Method not found: " + converter + ".[unnamed] " + methodErrorName ));
168+ "Method not found: " + methodErrorName + " on " + converters ));
165169 if (!mapping .getModifiers ().contains (Modifier .PUBLIC )) {
166- throw new IllegalArgumentException ("Method is not public: " + converter + "." + mapping );
170+ throw new IllegalArgumentException (
171+ "Method is not public: " + mapping .getEnclosingElement () + "." + mapping );
167172 }
168173 if (mapping .getModifiers ().contains (Modifier .STATIC )) {
169174 return CodeBlock .of (
170- converter .equals (targetType )
171- ? mapping .getSimpleName ()
172- : converter .getQualifiedName () + "." + mapping .getSimpleName (),
173- "(ctx)" );
175+ mapping .getEnclosingElement ().asType () + "." + mapping .getSimpleName (), "(ctx)" );
174176 } else {
175- if (converter .equals (targetType )) {
177+ if (mapping . getEnclosingElement () .equals (targetType )) {
176178 return CodeBlock .of ("c." + mapping .getSimpleName (), "(ctx)" );
177179 } else {
178- throw new IllegalArgumentException ("Not a static method: " + converter + "." + mapping );
180+ if (mapping .getKind () == ElementKind .CONSTRUCTOR ) {
181+ return CodeBlock .of (kt ? "" : "new " , type .getName (), "(ctx)" );
182+ }
183+ throw new IllegalArgumentException (
184+ "Not a static method: " + mapping .getEnclosingElement () + "." + mapping );
179185 }
180186 }
181187 }
0 commit comments