Skip to content

Commit e477f13

Browse files
SentryManrbygrave
andauthored
Use avaje spi for service validation when available (#456)
* use avaje spi for service validation if possible * Update pom.xml * Format changes only --------- Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
1 parent 5c2ee0d commit e477f13

File tree

4 files changed

+50
-46
lines changed

4 files changed

+50
-46
lines changed

http-generator-client/src/main/java/io/avaje/http/generator/client/ClientProcessor.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import javax.lang.model.element.Element;
1818
import javax.lang.model.element.TypeElement;
1919

20+
import io.avaje.http.generator.core.APContext;
2021
import io.avaje.http.generator.core.ClientPrism;
2122
import io.avaje.http.generator.core.ControllerReader;
2223
import io.avaje.http.generator.core.ImportPrism;
@@ -44,14 +45,15 @@ public SourceVersion getSupportedSourceVersion() {
4445
public synchronized void init(ProcessingEnvironment processingEnv) {
4546
super.init(processingEnv);
4647
this.processingEnv = processingEnv;
48+
APContext.init(processingEnv);
4749
ProcessingContext.init(processingEnv, new ClientPlatformAdapter(), false);
4850
this.componentWriter = new SimpleComponentWriter(metaData);
4951
useJsonB = ProcessingContext.useJsonb();
5052
}
5153

5254
@Override
5355
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment round) {
54-
ProcessingContext.findModule(annotations, round);
56+
APContext.setProjectModuleElement(annotations, round);
5557
final var platform = platform();
5658
if (!(platform instanceof ClientPlatformAdapter)) {
5759
setPlatform(new ClientPlatformAdapter());
@@ -107,7 +109,8 @@ protected String writeClientAdapter(ControllerReader reader) throws IOException
107109
private void initialiseComponent() {
108110
metaData.initialiseFullName();
109111
if (!metaData.all().isEmpty()) {
110-
ProcessingContext.validateModule(metaData.fullName());
112+
ProcessingContext.addClientComponent(metaData.fullName());
113+
ProcessingContext.validateModule();
111114
}
112115
try {
113116
componentWriter.init();

http-generator-core/src/main/java/io/avaje/http/generator/core/BaseProcessor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
import javax.lang.model.element.TypeElement;
2323
import javax.lang.model.util.ElementFilter;
2424

25+
import io.avaje.prism.GenerateAPContext;
26+
import io.avaje.prism.GenerateModuleInfoReader;
27+
28+
@GenerateAPContext
29+
@GenerateModuleInfoReader
2530
@SupportedOptions({"useJavax", "useSingleton", "instrumentRequests","disableDirectWrites"})
2631
public abstract class BaseProcessor extends AbstractProcessor {
2732

@@ -42,6 +47,7 @@ public Set<String> getSupportedAnnotationTypes() {
4247
@Override
4348
public synchronized void init(ProcessingEnvironment processingEnv) {
4449
super.init(processingEnv);
50+
APContext.init(processingEnv);
4551
ProcessingContext.init(processingEnv, providePlatformAdapter());
4652
}
4753

@@ -51,7 +57,7 @@ public synchronized void init(ProcessingEnvironment processingEnv) {
5157
@Override
5258
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment round) {
5359
var pathElements = round.getElementsAnnotatedWith(typeElement(PathPrism.PRISM_TYPE));
54-
60+
APContext.setProjectModuleElement(annotations, round);
5561
if (contextPathString == null) {
5662
contextPathString =
5763
ElementFilter.modulesIn(pathElements).stream()
@@ -79,6 +85,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
7985

8086
if (round.processingOver()) {
8187
writeOpenAPI();
88+
ProcessingContext.validateModule();
8289
}
8390
return false;
8491
}

http-generator-core/src/main/java/io/avaje/http/generator/core/ProcessingContext.java

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
package io.avaje.http.generator.core;
22

3-
import java.io.BufferedReader;
43
import java.io.IOException;
5-
import java.io.InputStreamReader;
64
import java.net.URI;
75
import java.nio.file.Paths;
8-
import java.util.Collection;
96
import java.util.List;
107
import java.util.Objects;
118
import java.util.Optional;
12-
import java.util.Set;
139
import java.util.stream.Collectors;
1410
import java.util.stream.Stream;
1511

1612
import javax.annotation.processing.Filer;
1713
import javax.annotation.processing.Messager;
1814
import javax.annotation.processing.ProcessingEnvironment;
19-
import javax.annotation.processing.RoundEnvironment;
2015
import javax.lang.model.element.Element;
2116
import javax.lang.model.element.ExecutableElement;
2217
import javax.lang.model.element.ModuleElement;
@@ -31,6 +26,7 @@
3126
import javax.tools.JavaFileObject;
3227
import javax.tools.StandardLocation;
3328

29+
import io.avaje.http.generator.core.ModuleInfoReader.Provides;
3430
import io.avaje.http.generator.core.openapi.DocContext;
3531

3632
public 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
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<nexus.staging.autoReleaseAfterClose>true</nexus.staging.autoReleaseAfterClose>
2222
<swagger.version>2.2.22</swagger.version>
2323
<jackson.version>2.14.2</jackson.version>
24-
<avaje.prisms.version>1.24</avaje.prisms.version>
24+
<avaje.prisms.version>1.25</avaje.prisms.version>
2525
<module-info.shade>${project.build.directory}${file.separator}module-info.shade</module-info.shade>
2626
</properties>
2727

0 commit comments

Comments
 (0)