Skip to content

Commit

Permalink
Merge pull request #366 from gdgib/G2-1554-ServiceFilesInSourceOutput
Browse files Browse the repository at this point in the history
G2-1554 Move service annotation output to source_output
  • Loading branch information
gdgib authored Apr 6, 2024
2 parents fd5ae77 + f5d8062 commit 059bb41
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
Expand All @@ -28,7 +29,7 @@

import lombok.RequiredArgsConstructor;

@SupportedSourceVersion(SourceVersion.RELEASE_11)
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class AnnotationProcessor extends AbstractProcessor {
@RequiredArgsConstructor
protected static class PathSupplier implements Supplier<String> {
Expand Down Expand Up @@ -95,11 +96,12 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment

final Class<? extends IAnnotationHandler<?>> handlerType = handlerAnnotation.value();
try {
Constructor<? extends IAnnotationHandler<?>> constructor = handlerType.getConstructor();
@SuppressWarnings({ "unchecked", "rawtypes" })
final IAnnotationHandler<Annotation> temp = (IAnnotationHandler) handlerType.newInstance();
final IAnnotationHandler<Annotation> temp = (IAnnotationHandler) constructor.newInstance();
return temp;
} catch (InstantiationException | IllegalAccessException exception) {
throw new Error(String.format("Failed to instantiate annotation handler for %1$s", at.getName()), exception);
} catch (Throwable throwable) {
throw new Error(String.format("Failed to instantiate annotation handler for %1$s", at.getName()), throwable);
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,55 +9,70 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Supplier;

import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.JavaFileManager.Location;
import javax.tools.StandardLocation;

import com.g2forge.alexandria.annotations.ElementAnnotations;
import com.g2forge.alexandria.annotations.HAnnotationProcessor;
import com.g2forge.alexandria.annotations.IAnnotationHandler;

public class ServiceAnnotationHandler implements IAnnotationHandler<Service> {
protected static void readImplementations(final Collection<String> retVal, ProcessingEnvironment processingEnvironment, final String fileName, final StandardLocation location) throws IOException {
protected static boolean ENABLE_DEBUGGING = false;

protected static void debug(ProcessingEnvironment processingEnvironment, Supplier<String> message) {
if (ENABLE_DEBUGGING) processingEnvironment.getMessager().printMessage(Diagnostic.Kind.WARNING, message.get());
}

protected static final Location[] READ_LOCATIONS = new Location[] { StandardLocation.CLASS_OUTPUT, StandardLocation.SOURCE_OUTPUT, StandardLocation.CLASS_PATH, StandardLocation.SOURCE_PATH };

protected static Set<String> readImplementations(ProcessingEnvironment processingEnvironment, final String fileName, final Location location) throws IOException {
final FileObject inputResource;

try {
inputResource = processingEnvironment.getFiler().getResource(location, "", fileName);
} catch (FileNotFoundException | IllegalArgumentException exception) {
// processingEnvironment.getMessager().printMessage(Diagnostic.Kind.WARNING, HAnnotationProcessor.toString(exception));
return;
debug(processingEnvironment, () -> HAnnotationProcessor.toString(exception));
return Collections.emptySet();
}

try (final BufferedReader inputReader = new BufferedReader(inputResource.openReader(true))) {
final Set<String> retVal = new LinkedHashSet<>();
for (String line = inputReader.readLine(); line != null; line = inputReader.readLine()) {
retVal.add(line);
}
return retVal;
} catch (FileNotFoundException | NoSuchFileException exception) {
// processingEnvironment.getMessager().printMessage(Diagnostic.Kind.WARNING, HAnnotationProcessor.toString(exception));
return;
debug(processingEnvironment, () -> HAnnotationProcessor.toString(exception));
return Collections.emptySet();
} catch (IOException exception) {
// processingEnvironment.getMessager().printMessage(Diagnostic.Kind.WARNING, HAnnotationProcessor.toString(exception));
if (exception.getMessage().contains("does not exist")) return;
debug(processingEnvironment, () -> HAnnotationProcessor.toString(exception));
if (exception.getMessage().contains("does not exist")) return Collections.emptySet();
throw exception;
}
}

protected static void writeImplementations(final ProcessingEnvironment processingEnvironment, final StandardLocation location, final String fileName, List<Element> elements, final List<String> list) throws IOException {
final FileObject outputResource = processingEnvironment.getFiler().createResource(location, "", fileName, elements.toArray(new Element[0]));
protected static void writeImplementations(final ProcessingEnvironment processingEnvironment, final StandardLocation location, final String fileName, Map<String, Element> implementations) throws IOException {
debug(processingEnvironment, () -> "Writing " + fileName + " to " + location);
final FileObject outputResource = processingEnvironment.getFiler().createResource(location, "", fileName, implementations.values().toArray(Element[]::new));
try (final PrintStream outputStream = new PrintStream(outputResource.openOutputStream())) {
list.forEach(outputStream::println);
implementations.keySet().forEach(outputStream::println);
}
}

Expand All @@ -66,23 +81,42 @@ protected static void writeImplementations(final ProcessingEnvironment processin
public void close(ProcessingEnvironment processingEnvironment) {
for (Map.Entry<String, List<Element>> entry : services.entrySet()) {
final String fileName = "META-INF/services/" + entry.getKey();
final Set<String> implementations = new HashSet<>();


try {
readImplementations(implementations, processingEnvironment, fileName, StandardLocation.SOURCE_PATH);
readImplementations(implementations, processingEnvironment, fileName, StandardLocation.CLASS_OUTPUT);

final Set<String> newServices = entry.getValue().stream().map(TypeElement.class::cast).map(TypeElement::getQualifiedName).map(Object::toString).collect(Collectors.toSet());
if (implementations.addAll(newServices)) {
final List<String> sorted = new ArrayList<>(implementations);
Collections.sort(sorted);
writeImplementations(processingEnvironment, StandardLocation.CLASS_OUTPUT, fileName, entry.getValue(), sorted);
final Set<String> existing;
final Map<String, Element> implementations = new TreeMap<>();
{
final Elements elements = processingEnvironment.getElementUtils();
Set<String> existing_ = null;
for (Location location : READ_LOCATIONS) {
final Set<String> loaded = readImplementations(processingEnvironment, fileName, location);
if (location == StandardLocation.SOURCE_OUTPUT) existing_ = new TreeSet<>(loaded);
for (String implementation : loaded) {
final TypeElement element = elements.getTypeElement(implementation);
if (element != null) implementations.put(implementation, element);
else processingEnvironment.getMessager().printMessage(Diagnostic.Kind.WARNING, "Service implementation " + implementation + " does not exist, removing");
}
}
existing = existing_;
}

for (Element element : entry.getValue()) {
final TypeElement typeElement = (TypeElement) element;
implementations.put(typeElement.getQualifiedName().toString(), element);
}

debug(processingEnvironment, () -> "Existing: " + existing.toString());
debug(processingEnvironment, () -> "Implementations: " + implementations.keySet());
if (existing == null || !existing.equals(implementations.keySet())) {
writeImplementations(processingEnvironment, StandardLocation.CLASS_OUTPUT, fileName, implementations);
}
} catch (Throwable throwable) {
final Messager messager = processingEnvironment.getMessager();
for (Element element : entry.getValue()) {
final String className = ((TypeElement) element).getQualifiedName().toString();
messager.printMessage(Diagnostic.Kind.ERROR, "Could not create resource \"" + fileName + " to add service \"" + className + "\"\": " + HAnnotationProcessor.toString(throwable), element);
final String message = "Could not create resource \"" + fileName + " to add service \"" + className + "\"\": " + HAnnotationProcessor.toString(throwable);
messager.printMessage(Diagnostic.Kind.ERROR, message, element);
debug(processingEnvironment, () -> message);
}
}
}
Expand Down

0 comments on commit 059bb41

Please sign in to comment.