Skip to content

Support qualifiers with members #488

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/jdk-ea.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
java_version: [GA,22-ea,EA] ## valhalla (fails javadoc)
java_version: [GA,EA] ## valhalla (fails javadoc)
os: [ubuntu-latest]

steps:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,31 @@
package io.avaje.inject.generator;

import static java.util.stream.Collectors.toList;

import java.util.List;
import java.util.Map.Entry;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;

final class AnnotationCopier {
private AnnotationCopier() {}

public static void copyAnnotations(Append writer, Element element, boolean newLines) {
static void copyAnnotations(Append writer, Element element, boolean newLines) {
copyAnnotations(writer, element, "", newLines);
}

public static void copyAnnotations(Append writer, Element element, String indent, boolean newLines) {
static void copyAnnotations(Append writer, Element element, String indent, boolean newLines) {
for (final AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
final var type = annotationMirror.getAnnotationType().asElement().asType().toString();
if (type.startsWith("io.avaje.inject.Assist")) {
continue;
}
final String annotationName = annotationMirror.getAnnotationType().toString();
final StringBuilder sb = new StringBuilder(indent).append("@").append(annotationName).append("(");
boolean first = true;

for (final var entry : annotationMirror.getElementValues().entrySet()) {
if (!first) {
sb.append(", ");
}
sb.append(entry.getKey().getSimpleName()).append("=");
writeVal(sb, entry.getValue());
first = false;
}

sb.append(")");
final String annotationString = sb.toString();
final String annotationString = toAnnotationString(indent, annotationMirror, false);
writer.append(annotationString);

if (newLines) {
Expand All @@ -45,8 +36,41 @@ public static void copyAnnotations(Append writer, Element element, String indent
}
}

static String toSimpleAnnotationString(AnnotationMirror annotationMirror) {
return Util.trimAnnotationString(toAnnotationString("", annotationMirror, true)).substring(1);
}

static String toAnnotationString(String indent, AnnotationMirror annotationMirror, boolean simpleEnums) {
final String annotationName = annotationMirror.getAnnotationType().toString();

final StringBuilder sb = new StringBuilder(indent).append("@").append(annotationName).append("(");
boolean first = true;

for (final var entry : sortedValues(annotationMirror)) {
if (!first) {
sb.append(", ");
}
sb.append(entry.getKey().getSimpleName()).append("=");
writeVal(sb, entry.getValue(), simpleEnums);
first = false;
}

return sb.append(")").toString().replace("()", "");
}

private static List<Entry<? extends ExecutableElement, ? extends AnnotationValue>> sortedValues(AnnotationMirror annotationMirror) {
return APContext.elements().getElementValuesWithDefaults(annotationMirror).entrySet().stream()
.sorted(AnnotationCopier::compareBySimpleName)
.collect(toList());
}

private static int compareBySimpleName(Entry<? extends ExecutableElement, ? extends AnnotationValue> entry1,
Entry<? extends ExecutableElement, ? extends AnnotationValue> entry2) {
return entry1.getKey().getSimpleName().toString().compareTo(entry2.getKey().getSimpleName().toString());
}

@SuppressWarnings("unchecked")
private static void writeVal(final StringBuilder sb, final AnnotationValue annotationValue) {
private static void writeVal(final StringBuilder sb, final AnnotationValue annotationValue, boolean simpleEnums) {
final var value = annotationValue.getValue();
if (value instanceof List) {
// handle array values
Expand All @@ -56,7 +80,7 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
if (!first) {
sb.append(", ");
}
writeVal(sb, listValue);
writeVal(sb, listValue, simpleEnums);
first = false;
}
sb.append("}");
Expand All @@ -65,7 +89,8 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
// Handle enum values
final var element = (VariableElement) value;
final var type = element.asType();
sb.append(type.toString() + "." + element);
final var str = simpleEnums ? element : type.toString() + "." + element;
sb.append(str);

} else if (value instanceof AnnotationMirror) {
// handle annotation values
Expand All @@ -74,12 +99,12 @@ private static void writeVal(final StringBuilder sb, final AnnotationValue annot
sb.append("@").append(annotationName).append("(");
boolean first = true;

for (final var entry : mirror.getElementValues().entrySet()) {
for (final var entry : sortedValues(mirror)) {
if (!first) {
sb.append(", ");
}
sb.append(entry.getKey().getSimpleName()).append("=");
writeVal(sb, entry.getValue());
writeVal(sb, entry.getValue(), simpleEnums);
first = false;
}
sb.append(")");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
Expand Down Expand Up @@ -35,7 +36,8 @@
Constants.TESTSCOPE,
Constants.CONTROLLER,
ImportPrism.PRISM_TYPE,
AspectImportPrism.PRISM_TYPE
AspectImportPrism.PRISM_TYPE,
QualifierPrism.PRISM_TYPE
})
public final class Processor extends AbstractProcessor {

Expand Down Expand Up @@ -103,6 +105,11 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment

readBeans(delayedElements());
addImportedAspects(importedAspects(roundEnv));
maybeElements(roundEnv, QualifierPrism.PRISM_TYPE).stream()
.flatMap(Set::stream)
.flatMap(e -> ElementFilter.methodsIn(e.getEnclosedElements()).stream())
.forEach(this::validateQualifier);

maybeElements(roundEnv, ScopePrism.PRISM_TYPE).ifPresent(this::readScopes);
maybeElements(roundEnv, FactoryPrism.PRISM_TYPE).ifPresent(this::readFactories);

Expand All @@ -128,6 +135,19 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
return false;
}

private void validateQualifier(ExecutableElement method) {
var type = APContext.asTypeElement(method.getReturnType());
if (type == null || type.getKind() != ElementKind.ANNOTATION_TYPE) {
return;
}

var enclosedMethods = ElementFilter.methodsIn(type.getEnclosedElements());
if (enclosedMethods.size() > 1) {
APContext.logError(method, "Qualifier annotation members can only have a single attribute");
}
enclosedMethods.forEach(this::validateQualifier);
}

// Optional because these annotations are not guaranteed to exist
private static Optional<? extends Set<? extends Element>> maybeElements(RoundEnvironment round, String name) {
return Optional.ofNullable(typeElement(name)).map(round::getElementsAnnotatedWith);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
package io.avaje.inject.generator;

import static io.avaje.inject.generator.APContext.logWarn;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;

import static io.avaje.inject.generator.APContext.logWarn;

/**
* Read the annotations on the type.
*/
final class TypeAnnotationReader {

private final TypeElement beanType;
private final List<String> annotationTypes = new ArrayList<>();
private String qualifierName;

TypeAnnotationReader(TypeElement beanType) {
this.beanType = beanType;
}

List<String> annotationTypes() {
return annotationTypes;
}

boolean hasQualifierName() {
return qualifierName != null;
Expand All @@ -38,13 +31,16 @@ void process() {
for (AnnotationMirror annotationMirror : beanType.getAnnotationMirrors()) {
DeclaredType annotationType = annotationMirror.getAnnotationType();
String annType = annotationType.toString();

if (QualifierPrism.isPresent(annotationType.asElement())) {
qualifierName = Util.shortName(annType).toLowerCase();
var shortName = Util.shortName(annotationType.toString());
qualifierName = AnnotationCopier.toSimpleAnnotationString(annotationMirror)
.replaceFirst(annotationType.toString(), shortName)
.replace("\"", "\\\"")
.toLowerCase();

} else if (annType.indexOf('.') == -1) {
logWarn("skip when no package on annotation " + annType);
} else if (IncludeAnnotations.include(annType)) {
annotationTypes.add(annType);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package io.avaje.inject.generator;

import static io.avaje.inject.generator.APContext.logWarn;
import static io.avaje.inject.generator.APContext.typeElement;
import static io.avaje.inject.generator.APContext.types;
import static io.avaje.inject.generator.ProcessingContext.asElement;
import static java.util.stream.Collectors.toList;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -33,7 +30,6 @@ final class TypeExtendsReader {
private final List<UType> interfaceTypes = new ArrayList<>();
private final List<UType> providesTypes = new ArrayList<>();
private final String beanSimpleName;
private final String baseTypeRaw;
private final boolean baseTypeIsInterface;
private final boolean publicAccess;
private final boolean autoProvide;
Expand All @@ -50,7 +46,6 @@ final class TypeExtendsReader {
this.baseType = baseType;
this.extendsInjection = new TypeExtendsInjection(baseType, factory, importTypes);
this.beanSimpleName = baseType.getSimpleName().toString();
this.baseTypeRaw = Util.unwrapProvider(baseUType.toString());
this.baseTypeIsInterface = baseType.getKind() == ElementKind.INTERFACE;
this.publicAccess = baseType.getModifiers().contains(Modifier.PUBLIC);
this.autoProvide = autoProvide();
Expand Down
Loading