11package io .avaje .http .generator .core ;
22
3- import static io .avaje .http .generator .core .ProcessingContext .doc ;
4- import static io .avaje .http .generator .core .ProcessingContext .elements ;
5- import static io .avaje .http .generator .core .ProcessingContext .isOpenApiAvailable ;
6- import static io .avaje .http .generator .core .ProcessingContext .logError ;
7- import static io .avaje .http .generator .core .ProcessingContext .typeElement ;
3+ import static io .avaje .http .generator .core .ProcessingContext .*;
84import static java .util .stream .Collectors .toMap ;
95
106import java .io .IOException ;
1410import java .util .HashSet ;
1511import java .util .Map ;
1612import java .util .Map .Entry ;
13+ import java .util .Optional ;
1714import java .util .Set ;
1815
1916import javax .annotation .processing .AbstractProcessor ;
2219import javax .annotation .processing .SupportedOptions ;
2320import javax .lang .model .SourceVersion ;
2421import javax .lang .model .element .Element ;
22+ import javax .lang .model .element .ExecutableElement ;
23+ import javax .lang .model .element .Modifier ;
2524import javax .lang .model .element .TypeElement ;
2625import javax .lang .model .util .ElementFilter ;
2726
27+ import io .avaje .http .generator .core .TypeMap .CustomHandler ;
2828import io .avaje .prism .GenerateAPContext ;
2929import io .avaje .prism .GenerateModuleInfoReader ;
3030
@@ -54,7 +54,11 @@ public SourceVersion getSupportedSourceVersion() {
5454 @ Override
5555 public Set <String > getSupportedAnnotationTypes () {
5656 return Set .of (
57- PathPrism .PRISM_TYPE , ControllerPrism .PRISM_TYPE , OpenAPIDefinitionPrism .PRISM_TYPE );
57+ PathPrism .PRISM_TYPE ,
58+ ControllerPrism .PRISM_TYPE ,
59+ OpenAPIDefinitionPrism .PRISM_TYPE ,
60+ MappedParamPrism .PRISM_TYPE ,
61+ MapImportPrism .PRISM_TYPE );
5862 }
5963
6064 @ Override
@@ -65,7 +69,6 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
6569
6670 try {
6771 var txtFilePath = APContext .getBuildResource (HTTP_CONTROLLERS_TXT );
68-
6972 if (txtFilePath .toFile ().exists ()) {
7073 Files .lines (txtFilePath ).forEach (clientFQNs ::add );
7174 }
@@ -75,8 +78,8 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
7578 }
7679 }
7780 } catch (IOException e ) {
78- e .printStackTrace ();
7981 // not worth failing over
82+ logWarn ("Error reading test controllers %s" , e );
8083 }
8184 }
8285
@@ -88,6 +91,17 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
8891 if (round .errorRaised ()) {
8992 return false ;
9093 }
94+
95+ for (final var type : ElementFilter .typesIn (getElements (round , MappedParamPrism .PRISM_TYPE ))) {
96+ var prism = MappedParamPrism .getInstanceOn (type );
97+ registerParamMapping (type , prism .factoryMethod ());
98+ }
99+
100+ for (final var type : getElements (round , MapImportPrism .PRISM_TYPE )) {
101+ var prism = MapImportPrism .getInstanceOn (type );
102+ registerParamMapping (APContext .asTypeElement (prism .value ()), prism .factoryMethod ());
103+ }
104+
91105 var pathElements = round .getElementsAnnotatedWith (typeElement (PathPrism .PRISM_TYPE ));
92106 APContext .setProjectModuleElement (annotations , round );
93107 if (contextPathString == null ) {
@@ -111,9 +125,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
111125 readSecuritySchemes (round );
112126 }
113127
114- for (final var controller :
115- ElementFilter .typesIn (
116- round .getElementsAnnotatedWith (typeElement (ControllerPrism .PRISM_TYPE )))) {
128+ for (final var controller : ElementFilter .typesIn (round .getElementsAnnotatedWith (typeElement (ControllerPrism .PRISM_TYPE )))) {
117129 writeAdapter (controller );
118130 }
119131
@@ -136,9 +148,33 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
136148 return false ;
137149 }
138150
151+ private Set <? extends Element > getElements (RoundEnvironment round , String name ) {
152+ return Optional .ofNullable (typeElement (name ))
153+ .map (round ::getElementsAnnotatedWith )
154+ .orElse (Set .of ());
155+ }
156+
157+ private final void registerParamMapping (final TypeElement type , String factoryMethod ) {
158+ if (factoryMethod .isBlank ()) {
159+ Util .stringConstructor (type )
160+ .ifPresentOrElse (
161+ c -> TypeMap .add (new CustomHandler (UType .parse (type .asType ()), "" )),
162+ () -> logError (type , "Missing constructor %s(String s)" ));
163+
164+ } else {
165+ ElementFilter .methodsIn (type .getEnclosedElements ()).stream ()
166+ .filter (m -> m .getSimpleName ().contentEquals (factoryMethod )
167+ && m .getModifiers ().contains (Modifier .STATIC )
168+ && Util .singleStringParam (m ))
169+ .findAny ()
170+ .ifPresentOrElse (
171+ c -> TypeMap .add (new CustomHandler (UType .parse (type .asType ()), factoryMethod )),
172+ () -> logError (type , "Missing static factory method %s(String s)" , factoryMethod ));
173+ }
174+ }
175+
139176 private void readOpenApiDefinition (RoundEnvironment round ) {
140- for (final Element element :
141- round .getElementsAnnotatedWith (typeElement (OpenAPIDefinitionPrism .PRISM_TYPE ))) {
177+ for (final Element element : round .getElementsAnnotatedWith (typeElement (OpenAPIDefinitionPrism .PRISM_TYPE ))) {
142178 doc ().readApiDefinition (element );
143179 }
144180 }
@@ -147,19 +183,16 @@ private void readTagDefinitions(RoundEnvironment round) {
147183 for (final Element element : round .getElementsAnnotatedWith (typeElement (TagPrism .PRISM_TYPE ))) {
148184 doc ().addTagDefinition (element );
149185 }
150- for (final Element element :
151- round .getElementsAnnotatedWith (typeElement (TagsPrism .PRISM_TYPE ))) {
186+ for (final Element element : round .getElementsAnnotatedWith (typeElement (TagsPrism .PRISM_TYPE ))) {
152187 doc ().addTagsDefinition (element );
153188 }
154189 }
155190
156191 private void readSecuritySchemes (RoundEnvironment round ) {
157- for (final Element element :
158- round .getElementsAnnotatedWith (typeElement (SecuritySchemePrism .PRISM_TYPE ))) {
192+ for (final Element element : round .getElementsAnnotatedWith (typeElement (SecuritySchemePrism .PRISM_TYPE ))) {
159193 doc ().addSecurityScheme (element );
160194 }
161- for (final Element element :
162- round .getElementsAnnotatedWith (typeElement (SecuritySchemesPrism .PRISM_TYPE ))) {
195+ for (final Element element : round .getElementsAnnotatedWith (typeElement (SecuritySchemesPrism .PRISM_TYPE ))) {
163196 doc ().addSecuritySchemes (element );
164197 }
165198 }
@@ -174,7 +207,6 @@ private void writeAdapter(TypeElement controller) {
174207 final var reader = new ControllerReader (controller , contextPath );
175208 reader .read (true );
176209 try {
177-
178210 writeControllerAdapter (reader );
179211 writeClientAdapter (reader );
180212
@@ -184,7 +216,6 @@ private void writeAdapter(TypeElement controller) {
184216 }
185217
186218 private void writeClientAdapter (ControllerReader reader ) {
187-
188219 try {
189220 if (reader .beanType ().getInterfaces ().isEmpty ()
190221 && "java.lang.Object" .equals (reader .beanType ().getSuperclass ().toString ())
0 commit comments