11package io .avaje .http .generator .core ;
22
3- import java .io .BufferedReader ;
43import java .io .IOException ;
5- import java .io .InputStreamReader ;
64import java .net .URI ;
75import java .nio .file .Paths ;
8- import java .util .Collection ;
96import java .util .List ;
107import java .util .Objects ;
118import java .util .Optional ;
12- import java .util .Set ;
139import java .util .stream .Collectors ;
1410import java .util .stream .Stream ;
1511
1612import javax .annotation .processing .Filer ;
1713import javax .annotation .processing .Messager ;
1814import javax .annotation .processing .ProcessingEnvironment ;
19- import javax .annotation .processing .RoundEnvironment ;
2015import javax .lang .model .element .Element ;
2116import javax .lang .model .element .ExecutableElement ;
2217import javax .lang .model .element .ModuleElement ;
3126import javax .tools .JavaFileObject ;
3227import javax .tools .StandardLocation ;
3328
29+ import io .avaje .http .generator .core .ModuleInfoReader .Provides ;
3430import io .avaje .http .generator .core .openapi .DocContext ;
3531
3632public final class ProcessingContext {
@@ -53,8 +49,9 @@ private static final class Ctx {
5349 private final boolean instrumentAllMethods ;
5450 private final boolean disableDirectWrites ;
5551 private final boolean javalin6 ;
56- private ModuleElement module ;
52+ private final boolean spiPresent = APContext . typeElement ( "io.avaje.spi.internal.ServiceProcessor" ) != null ;
5753 private boolean validated ;
54+ private String clientFQN ;
5855
5956 Ctx (ProcessingEnvironment env , PlatformAdapter adapter , boolean generateOpenAPI ) {
6057 readAdapter = adapter ;
@@ -146,7 +143,12 @@ public static JavaFileObject createWriter(String cls, Element origin) throws IOE
146143
147144 /** Create a file writer for the META-INF services file. */
148145 public static FileObject createMetaInfWriter (String target ) throws IOException {
149- return CTX .get ().filer .createResource (StandardLocation .CLASS_OUTPUT , "" , target );
146+ var serviceFile =
147+ CTX .get ().spiPresent
148+ ? target .replace ("META-INF/services/" , "META-INF/generated-services/" )
149+ : target ;
150+
151+ return filer ().createResource (StandardLocation .CLASS_OUTPUT , "" , serviceFile );
150152 }
151153
152154 public static JavaFileObject createWriter (String cls ) throws IOException {
@@ -175,7 +177,7 @@ public static List<ExecutableElement> superMethods(Element element, String metho
175177 .filter (type -> !type .toString ().contains ("java.lang.Object" ))
176178 .map (superType -> {
177179 final var superClass = (TypeElement ) types .asElement (superType );
178- for (final ExecutableElement method : ElementFilter .methodsIn (CTX .get ().elementUtils .getAllMembers (superClass ))) {
180+ for (final var method : ElementFilter .methodsIn (CTX .get ().elementUtils .getAllMembers (superClass ))) {
179181 if (method .getSimpleName ().contentEquals (methodName )) {
180182 return method ;
181183 }
@@ -231,45 +233,33 @@ public static boolean isAssignable2Interface(String type, String superType) {
231233 static Stream <String > superTypes (Element element ) {
232234 final Types types = CTX .get ().typeUtils ;
233235 return types .directSupertypes (element .asType ()).stream ()
234- .filter (type -> !type .toString ().contains ("java.lang.Object" ))
235- .map (superType -> (TypeElement ) types .asElement (superType ))
236- .flatMap (e -> Stream .concat (superTypes (e ), Stream .of (e )))
237- .map (Object ::toString );
238- }
239-
240- public static void findModule (Set <? extends TypeElement > annotations , RoundEnvironment roundEnv ) {
241- if (CTX .get ().module == null ) {
242- CTX .get ().module =
243- annotations .stream ()
244- .map (roundEnv ::getElementsAnnotatedWith )
245- .flatMap (Collection ::stream )
246- .findAny ()
247- .map (ProcessingContext ::getModuleElement )
248- .orElse (null );
249- }
236+ .filter (type -> !type .toString ().contains ("java.lang.Object" ))
237+ .map (superType -> (TypeElement ) types .asElement (superType ))
238+ .flatMap (e -> Stream .concat (superTypes (e ), Stream .of (e )))
239+ .map (Object ::toString );
250240 }
251241
252- public static void validateModule (String fqn ) {
253- var module = CTX . get (). module ;
242+ public static void validateModule () {
243+ var module = APContext . getProjectModuleElement () ;
254244 if (module != null && !CTX .get ().validated && !module .isUnnamed ()) {
255-
256245 CTX .get ().validated = true ;
257- try (var inputStream =
258- CTX . get ()
259- . filer
260- . getResource ( StandardLocation . SOURCE_PATH , "" , "module-info.java" )
261- . toUri ()
262- . toURL ()
263- . openStream ( );
264- var reader = new BufferedReader ( new InputStreamReader ( inputStream ))) {
265-
266- var noProvides = reader . lines (). map ( s -> {
267- if ( s . contains ( "io.avaje.http.api.javalin" ) && ! s . contains ( "static" )) {
268- logWarn ( "io.avaje.http.api.javalin only contains SOURCE retention annotations. It should added as `requires static`" );
269- }
270- return s ;
271- } )
246+ try (var bufferedReader = APContext . getModuleInfoReader ()) {
247+ var reader = new ModuleInfoReader ( module , bufferedReader );
248+ reader . requires (). forEach ( r -> {
249+ if (! r . isStatic () && r . getDependency (). getQualifiedName (). contentEquals ( "io.avaje.http.api.javalin" )) {
250+ logWarn ( module , "io.avaje.http.api.javalin only contains SOURCE retention annotations. It should added as `requires static`" );
251+ }
252+ } );
253+ var fqn = CTX . get (). clientFQN ;
254+ if ( CTX . get (). spiPresent || fqn == null ) {
255+ return ;
256+ }
257+ var noProvides = reader . provides (). stream ()
258+ . filter ( p -> "io.avaje.http.client.HttpClient.GeneratedComponent" . equals ( p . service ()))
259+ . map ( Provides :: implementations )
260+ . flatMap ( List :: stream )
272261 .noneMatch (s -> s .contains (fqn ));
262+
273263 if (noProvides && !buildPluginAvailable ()) {
274264 logError (module , "Missing `provides io.avaje.http.client.HttpClient.GeneratedComponent with %s;`" , fqn );
275265 }
@@ -309,4 +299,8 @@ private static boolean resourceExists(String relativeName) {
309299 return false ;
310300 }
311301 }
302+
303+ public static void addClientComponent (String clientFQN ) {
304+ CTX .get ().clientFQN = clientFQN ;
305+ }
312306}
0 commit comments