From c364026e709d6cafd203671f8bcbc3cb7f6fb0f5 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Thu, 7 Apr 2022 22:52:25 +0300 Subject: [PATCH 01/20] [0.18.0-SNAPSHOT] DynamicProxyHint draft added --- .../hint/annotation/DynamicProxyHint.java | 41 +++++++++++++++++++ gradle.properties | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java new file mode 100644 index 0000000..4ecb873 --- /dev/null +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java @@ -0,0 +1,41 @@ +package io.goodforgod.graalvm.hint.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @see GraalVM + * Info + * @author Anton Kurako (GoodforGod) + * @since 07.04.2022 + */ +@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE }) +@Retention(RetentionPolicy.SOURCE) +public @interface DynamicProxyHint { + + @Target({ ElementType.ANNOTATION_TYPE }) + @Retention(RetentionPolicy.SOURCE) + @interface DynamicProxyConfiguration { + + /** + * @return The interfaces to provide a hint (preferred because typesafe) + */ + Class[] interfaces() default {}; + + /** + * Alternative way to configure Interface names, should be used when type visibility + * prevents using {@link #interfaces()} references. + * + * @return the interface names + */ + String[] interfaceNames() default {}; + } + + DynamicProxyConfiguration[] configurations() default {}; + + String[] files() default {}; + + String[] resources() default {}; +} diff --git a/gradle.properties b/gradle.properties index 1938ec0..d3a7492 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ groupId=io.goodforgod artifactRootId=graalvm-hint -artifactVersion=0.17.1 +artifactVersion=0.18.0-SNAPSHOT ##### GRADLE ##### From 802bdd015034bae95ec41a1735b7bab2de2421de Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Fri, 8 Apr 2022 02:48:55 +0300 Subject: [PATCH 02/20] [0.18.0-SNAPSHOT] AbstractHintProcessor all methods as static and will be refactored future to util class AbstractHintProcessor#getAnnotationFieldClassNames with annotation value key predicate AbstractHintProcessor#writeConfigFile static HintOptions.java -> HintOrigin.java --- .../hint/annotation/DynamicProxyHint.java | 12 +- .../AbstractAccessHintProcessor.java | 4 +- .../hint/processor/AbstractHintProcessor.java | 105 ++++++++---------- .../{HintOptions.java => HintOrigin.java} | 6 +- .../hint/processor/JniHintProcessor.java | 14 +-- .../processor/ReflectionHintProcessor.java | 14 +-- .../hint/processor/ResourceHintProcessor.java | 8 +- 7 files changed, 73 insertions(+), 90 deletions(-) rename graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/{HintOptions.java => HintOrigin.java} (83%) diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java index 4ecb873..58380c4 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java @@ -17,23 +17,15 @@ @Target({ ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.SOURCE) - @interface DynamicProxyConfiguration { + @interface Configuration { /** * @return The interfaces to provide a hint (preferred because typesafe) */ Class[] interfaces() default {}; - - /** - * Alternative way to configure Interface names, should be used when type visibility - * prevents using {@link #interfaces()} references. - * - * @return the interface names - */ - String[] interfaceNames() default {}; } - DynamicProxyConfiguration[] configurations() default {}; + Configuration[] value() default {}; String[] files() default {}; diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java index a388900..c043763 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java @@ -116,7 +116,9 @@ public boolean process(Set annotations, RoundEnvironment return false; } - return writeConfigFile(getFileName(), configJson.get(), roundEnv); + final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final String filePath = origin.getRelativePathForFile(getFileName()); + return writeConfigFile(filePath, configJson.get(), processingEnv); } catch (Exception e) { e.printStackTrace(); return false; diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java index 3624d8b..f4eaee8 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java @@ -7,12 +7,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; +import javax.lang.model.element.*; import javax.lang.model.util.ElementFilter; import javax.tools.Diagnostic; import javax.tools.FileObject; @@ -24,8 +22,8 @@ */ abstract class AbstractHintProcessor extends AbstractProcessor { - private static final String DEFAULT_GROUP = "io.graalvm.hint"; - private static final String DEFAULT_ARTIFACT = "application"; + private static final String DEFAULT_PACKAGE = "io.graalvm.hint"; + private static final String DEFAULT_ARTIFACT = "hint"; @Override public SourceVersion getSupportedSourceVersion() { @@ -37,26 +35,26 @@ public SourceVersion getSupportedSourceVersion() { return SourceVersion.RELEASE_11; } } else { - return (SourceVersion.values())[17]; + return SourceVersion.values()[17]; } } - HintOptions getHintOptions(RoundEnvironment roundEnv) { + static HintOrigin getHintOrigin(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { final Map options = processingEnv.getOptions(); final Element anyElement = roundEnv.getRootElements().iterator().next(); - final String group = (options.containsKey(HintOptions.HINT_PROCESSING_GROUP)) - ? options.get(HintOptions.HINT_PROCESSING_GROUP) + final String group = (options.containsKey(HintOrigin.HINT_PROCESSING_GROUP)) + ? options.get(HintOrigin.HINT_PROCESSING_GROUP) : getPackage(anyElement); - final String artifact = (options.containsKey(HintOptions.HINT_PROCESSING_ARTIFACT)) - ? options.get(HintOptions.HINT_PROCESSING_ARTIFACT) + final String artifact = (options.containsKey(HintOrigin.HINT_PROCESSING_ARTIFACT)) + ? options.get(HintOrigin.HINT_PROCESSING_ARTIFACT) : getArtifact(anyElement); - return new HintOptions(group, artifact); + return new HintOrigin(group, artifact); } - Set getAnnotatedElements(RoundEnvironment roundEnv, Class... annotations) { + static Set getAnnotatedElements(RoundEnvironment roundEnv, Class... annotations) { return Arrays.stream(annotations) .flatMap(a -> { final Set annotated = roundEnv.getElementsAnnotatedWith(a); @@ -68,18 +66,18 @@ Set getAnnotatedElements(RoundEnvironment roundEnv, Class getAnnotationFieldClassNameAny(TypeElement type, - Class annotation, - String annotationFieldName) { + static Optional getAnnotationFieldClassNameAny(TypeElement type, + Class annotation, + String annotationFieldName) { final List classNames = getAnnotationFieldClassNames(type, annotation, annotationFieldName); return classNames.isEmpty() ? Optional.empty() : Optional.of(classNames.get(0)); } - List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName) { + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName) { final String annotationName = annotation.getSimpleName(); final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, annotationFieldName); return type.getAnnotationMirrors().stream() @@ -88,25 +86,35 @@ List getAnnotationFieldClassNames(TypeElement type, .collect(Collectors.toList()); } - List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName, - Class parentAnnotation) { + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName, + Class parentAnnotation) { return getAnnotationFieldClassNames(type, annotation, annotationFieldName, parentAnnotation, a -> true); } - List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName, - Class parentAnnotation, - Predicate annotationPredicate) { + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName, + Class parentAnnotation, + Predicate annotationPredicate) { + return getAnnotationFieldClassNames(type, annotation, annotationFieldName, parentAnnotation, annotationPredicate, + e -> e.getSimpleName().contentEquals("value")); + } + + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName, + Class parentAnnotation, + Predicate annotationPredicate, + Predicate parentAnnotationKeyPredicate) { final String annotationName = annotation.getSimpleName(); final String annotationParent = parentAnnotation.getSimpleName(); final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, annotationFieldName); return type.getAnnotationMirrors().stream() .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationParent)) .flatMap(a -> a.getElementValues().entrySet().stream() - .filter(e -> e.getKey().getSimpleName().contentEquals("value")) + .filter(e -> parentAnnotationKeyPredicate.test(e.getKey())) .flatMap(e -> ((List) e.getValue().getValue()).stream() .filter(an -> annotationPredicate.test(((AnnotationValue) an))) .flatMap(an -> ((AnnotationValue) an).accept(visitor, "").stream())) @@ -115,53 +123,32 @@ List getAnnotationFieldClassNames(TypeElement type, .collect(Collectors.toList()); } - boolean writeConfigFile(String fileName, - String data, - RoundEnvironment roundEnv) { - final HintOptions hintOptions = getHintOptions(roundEnv); - final String path = hintOptions.getRelativePathForFile(fileName); + static boolean writeConfigFile(String filePath, String data, ProcessingEnvironment processingEnv) { try { - final FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", path); + final FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filePath); try (Writer writer = fileObject.openWriter()) { writer.write(data); } } catch (Exception e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Couldn't write " + fileName + " due to: " + e.getMessage()); + "Couldn't write " + filePath + " due to: " + e.getMessage()); return false; } - processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Generating file " + fileName + " to: " + path); + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Generating file " + filePath + " to: " + filePath); return true; } - private String getPackage(Element element) { + private static String getPackage(Element element) { final Element enclosingElement = element.getEnclosingElement(); if (enclosingElement instanceof PackageElement) { - final String typeName = ((PackageElement) enclosingElement).getQualifiedName().toString(); - // class without package declare: unnamed package - if (!typeName.isEmpty()) { - return (typeName.contains(".")) - ? typeName.substring(0, typeName.lastIndexOf('.')) - : typeName; - } + return ((PackageElement) enclosingElement).getQualifiedName().toString(); } - return DEFAULT_GROUP; + return DEFAULT_PACKAGE; } - private String getArtifact(Element element) { - final Element enclosingElement = element.getEnclosingElement(); - if (enclosingElement instanceof PackageElement) { - final String typeName = ((PackageElement) enclosingElement).getQualifiedName().toString(); - // class without package declare: unnamed package - if (!typeName.isEmpty()) { - return (typeName.contains(".")) - ? typeName.substring(typeName.lastIndexOf('.') + 1) - : DEFAULT_ARTIFACT; - } - } - + private static String getArtifact(Element element) { return DEFAULT_ARTIFACT; } } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOptions.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java similarity index 83% rename from graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOptions.java rename to graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java index 70264db..10045b6 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOptions.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java @@ -1,12 +1,12 @@ package io.goodforgod.graalvm.hint.processor; /** - * Hint options that are registered to be used in GraalVM Hint Gradle Plugin + * Hint origin package and artifact * * @author Anton Kurako (GoodforGod) * @since 29.09.2021 */ -final class HintOptions { +final class HintOrigin { public static final String HINT_PROCESSING_GROUP = "graalvm.hint.group"; public static final String HINT_PROCESSING_ARTIFACT = "graalvm.hint.artifact"; @@ -21,7 +21,7 @@ final class HintOptions { */ private final String artifact; - HintOptions(String group, String artifact) { + HintOrigin(String group, String artifact) { this.group = group; this.artifact = artifact; } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java index 9e37457..ec992db 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java @@ -23,8 +23,8 @@ "io.goodforgod.graalvm.hint.annotation.JniHints" }) @SupportedOptions({ - HintOptions.HINT_PROCESSING_GROUP, - HintOptions.HINT_PROCESSING_ARTIFACT + HintOrigin.HINT_PROCESSING_GROUP, + HintOrigin.HINT_PROCESSING_ARTIFACT }) public final class JniHintProcessor extends AbstractAccessHintProcessor { @@ -52,17 +52,17 @@ protected Collection getGraalAccessForAnnotatedElement(TypeElement eleme final JniHints hints = element.getAnnotation(JniHints.class); if (hints == null) { final JniHint reflectionHint = element.getAnnotation(JniHint.class); - return getGraalReflectionsForAnnotatedElement(element, reflectionHint, false); + return getGraalAccessForAnnotatedElement(element, reflectionHint, false); } else { return Arrays.stream(hints.value()) - .flatMap(hint -> getGraalReflectionsForAnnotatedElement(element, hint, true).stream()) + .flatMap(hint -> getGraalAccessForAnnotatedElement(element, hint, true).stream()) .collect(Collectors.toList()); } } - private Collection getGraalReflectionsForAnnotatedElement(TypeElement element, - JniHint hint, - boolean isParentAnnotation) { + private Collection getGraalAccessForAnnotatedElement(TypeElement element, + JniHint hint, + boolean isParentAnnotation) { final ReflectionHint.AccessType[] accessTypes = convert(hint.value()); final List typeNames = Arrays.asList(hint.typeNames()); final List types = (!isParentAnnotation) diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java index 38a8807..bda3dce 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java @@ -23,8 +23,8 @@ "io.goodforgod.graalvm.hint.annotation.ReflectionHints" }) @SupportedOptions({ - HintOptions.HINT_PROCESSING_GROUP, - HintOptions.HINT_PROCESSING_ARTIFACT + HintOrigin.HINT_PROCESSING_GROUP, + HintOrigin.HINT_PROCESSING_ARTIFACT }) public final class ReflectionHintProcessor extends AbstractAccessHintProcessor { @@ -48,17 +48,17 @@ protected Collection getGraalAccessForAnnotatedElement(TypeElement eleme final ReflectionHints hints = element.getAnnotation(ReflectionHints.class); if (hints == null) { final ReflectionHint reflectionHint = element.getAnnotation(ReflectionHint.class); - return getGraalReflectionsForAnnotatedElement(element, reflectionHint, false); + return getGraalAccessForAnnotatedElement(element, reflectionHint, false); } else { return Arrays.stream(hints.value()) - .flatMap(hint -> getGraalReflectionsForAnnotatedElement(element, hint, true).stream()) + .flatMap(hint -> getGraalAccessForAnnotatedElement(element, hint, true).stream()) .collect(Collectors.toList()); } } - private Collection getGraalReflectionsForAnnotatedElement(TypeElement element, - ReflectionHint hint, - boolean isParentAnnotation) { + private Collection getGraalAccessForAnnotatedElement(TypeElement element, + ReflectionHint hint, + boolean isParentAnnotation) { final AccessType[] accessTypes = hint.value(); final List typeNames = Arrays.asList(hint.typeNames()); final List types = (!isParentAnnotation) diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java index 75b6bbd..f9c3e9f 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java @@ -18,8 +18,8 @@ */ @SupportedAnnotationTypes("io.goodforgod.graalvm.hint.annotation.ResourceHint") @SupportedOptions({ - HintOptions.HINT_PROCESSING_GROUP, - HintOptions.HINT_PROCESSING_ARTIFACT + HintOrigin.HINT_PROCESSING_GROUP, + HintOrigin.HINT_PROCESSING_ARTIFACT }) public final class ResourceHintProcessor extends AbstractHintProcessor { @@ -43,7 +43,9 @@ public boolean process(Set annotations, RoundEnvironment return false; } - return writeConfigFile(FILE_NAME, resourceConfigJson.get(), roundEnv); + final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final String filePath = origin.getRelativePathForFile(FILE_NAME); + return writeConfigFile(filePath, resourceConfigJson.get(), processingEnv); } catch (Exception e) { e.printStackTrace(); return false; From 697ac9989dc0e3bc2284a96bf95060c46c04b3ec Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Fri, 8 Apr 2022 02:51:08 +0300 Subject: [PATCH 03/20] [0.18.0-SNAPSHOT] OptionParser introduced InitializationHintParser and NativeImageHintParser extracted from NativeImageHintProcessor --- README.md | 4 +- .../processor/InitializationHintParser.java | 106 ++++++++++++++++++ .../hint/processor/NativeImageHintParser.java | 80 +++++++++++++ .../graalvm/hint/processor/OptionParser.java | 16 +++ 4 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java create mode 100644 graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java create mode 100644 graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java diff --git a/README.md b/README.md index fbbc9e9..ab6aeb5 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ public class EntrypointOnly { Resulted native-image.properties: ```properties -Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOptions.class \ +Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor ``` @@ -230,7 +230,7 @@ public class Entrypoint { Resulted native-image.properties: ```properties Args = -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint \ - --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOptions.class \ + --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor ``` diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java new file mode 100644 index 0000000..1556aeb --- /dev/null +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java @@ -0,0 +1,106 @@ +package io.goodforgod.graalvm.hint.processor; + +import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getAnnotatedElements; +import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getAnnotationFieldClassNames; + +import io.goodforgod.graalvm.hint.annotation.InitializationHint; +import io.goodforgod.graalvm.hint.annotation.InitializationHints; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; + +/** + * Processes {@link InitializationHint} annotations for native-image.properties file + * + * @author Anton Kurako (GoodforGod) + * @see InitializationHint + * @author Anton Kurako (GoodforGod) + * @since 07.04.2022 + */ +final class InitializationHintParser implements OptionParser { + + private static final String INIT_BUILD_TIME = "--initialize-at-build-time="; + private static final String INIT_RUNTIME_TIME = "--initialize-at-run-time="; + + private static class Initialization implements Comparable { + + private final String className; + private final InitializationHint.InitPhase phase; + + Initialization(String className, InitializationHint.InitPhase phase) { + this.className = className; + this.phase = phase; + } + + @Override + public int compareTo(Initialization o) { + return className.compareTo(o.className); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Initialization that = (Initialization) o; + return Objects.equals(className, that.className); + } + + @Override + public int hashCode() { + return Objects.hash(className); + } + } + + @Override + public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { + final Set elements = getAnnotatedElements(roundEnv, InitializationHint.class, InitializationHints.class); + + final Map> groupedInitializationOptions = elements.stream() + .flatMap(e -> { + final InitializationHints hints = e.getAnnotation(InitializationHints.class); + if (hints == null) { + final InitializationHint hint = e.getAnnotation(InitializationHint.class); + return getInitializations(e, hint, false); + } else { + return Arrays.stream(hints.value()) + .flatMap(h -> getInitializations(e, h, true)); + } + }) + .distinct() + .collect(Collectors.groupingBy(e -> e.phase)); + + return groupedInitializationOptions.entrySet().stream() + .map(e -> e.getValue().stream() + .sorted() + .map(i -> i.className) + .collect(Collectors.joining(",", getInitializationArgumentName(e.getKey()), ""))) + .sorted() + .collect(Collectors.toList()); + } + + private Stream getInitializations(TypeElement element, InitializationHint hint, boolean isParentAnnotation) { + final List types = (isParentAnnotation) + ? getAnnotationFieldClassNames(element, InitializationHint.class, "types", InitializationHints.class) + : getAnnotationFieldClassNames(element, InitializationHint.class, "types"); + + final List typeNames = Arrays.asList(hint.typeNames()); + if (types.isEmpty() && typeNames.isEmpty()) { + return Stream.of(new Initialization(element.getQualifiedName().toString(), hint.value())); + } else { + return Stream.of(types, typeNames) + .flatMap(Collection::stream) + .map(type -> new Initialization(type, hint.value())); + } + } + + private String getInitializationArgumentName(InitializationHint.InitPhase phase) { + return (InitializationHint.InitPhase.BUILD.equals(phase)) + ? INIT_BUILD_TIME + : INIT_RUNTIME_TIME; + } +} diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java new file mode 100644 index 0000000..c4af6a8 --- /dev/null +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java @@ -0,0 +1,80 @@ +package io.goodforgod.graalvm.hint.processor; + +import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getAnnotationFieldClassNameAny; + +import io.goodforgod.graalvm.hint.annotation.NativeImageHint; +import io.goodforgod.graalvm.hint.annotation.NativeImageOptions; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.ElementFilter; + +/** + * Processes {@link NativeImageHint} annotations for native-image.properties file + * + * @author Anton Kurako (GoodforGod) + * @see NativeImageHint + * @author Anton Kurako (GoodforGod) + * @since 07.04.2022 + */ +final class NativeImageHintParser implements OptionParser { + + private static final String ENTRY_POINT_DEFAULT_VALUE = Void.class.getSimpleName(); + + private static class Entrypoint { + + private final String className; + private final NativeImageHint hint; + + private Entrypoint(String className, NativeImageHint hint) { + this.className = className; + this.hint = hint; + } + } + + @Override + public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { + final Set annotatedNative = roundEnv.getElementsAnnotatedWith(NativeImageHint.class); + final Set elements = ElementFilter.typesIn(annotatedNative); + + final List entrypoints = elements.stream() + .map(t -> getAnnotationFieldClassNameAny(t, NativeImageHint.class, "entrypoint") + .filter(name -> !ENTRY_POINT_DEFAULT_VALUE.equals(name)) + .map(name -> new Entrypoint(name, t.getAnnotation(NativeImageHint.class))) + .orElse(null)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + if (entrypoints.size() > 1) { + throw new IllegalStateException("@NativeImageHint multiple entrypoint detected with values: " + entrypoints); + } + + final Optional entryClassName = entrypoints.stream().findFirst(); + final List options = elements.stream() + .map(element -> element.getAnnotation(NativeImageHint.class)) + .flatMap(hint -> Stream + .concat(Arrays.stream(hint.options()).map(NativeImageOptions::option), Arrays.stream(hint.optionNames())) + .distinct()) + .collect(Collectors.toList()); + + return entryClassName + .map(entry -> { + final List entryOptions = getEntrypointOptions(entry); + return Stream.of(entryOptions, options) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + }) + .orElse(options); + } + + private List getEntrypointOptions(Entrypoint entrypoint) { + return (entrypoint.hint.name().isBlank()) + ? List.of("-H:Class=" + entrypoint.className) + : List.of("-H:Name=" + entrypoint.hint.name() + " -H:Class=" + entrypoint.className); + } +} diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java new file mode 100644 index 0000000..1efaaaf --- /dev/null +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java @@ -0,0 +1,16 @@ +package io.goodforgod.graalvm.hint.processor; + +import java.util.List; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; + +/** + * Contract for hint parser that produces options + * + * @author Anton Kurako (GoodforGod) + * @since 07.04.2022 + */ +interface OptionParser { + + List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv); +} From 51de896ae3cb1544bf74b5969d3ab8c4d02828a2 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Fri, 8 Apr 2022 02:52:45 +0300 Subject: [PATCH 04/20] [0.18.0-SNAPSHOT] Tests imports and target package fixed --- .../hint/processor/InitializationHintProcessorTests.java | 6 +++--- .../graalvm/hint/processor/JniHintProcessorTests.java | 8 ++++---- .../hint/processor/NativeImageHintProcessorTests.java | 4 ++-- .../hint/processor/ReflectionHintProcessorTests.java | 8 ++++---- .../hint/processor/ResourceHintProcessorTests.java | 4 ++-- .../generated/native-image-build-runtime.properties | 2 +- .../generated/native-image-build.properties | 2 +- .../native-image-entrypoint-build-runtime.properties | 2 +- .../test/resources/initializationhint/source/Build.java | 2 +- .../initializationhint/source/BuildAndRuntime.java | 2 +- .../source/EntrypointAndBuildAndRuntime.java | 2 +- .../test/resources/jnihint/generated/jni-config-many.json | 2 +- .../src/test/resources/jnihint/generated/jni-config.json | 2 +- .../src/test/resources/jnihint/source/Response.java | 2 +- .../reflectionhint/generated/reflect-config-many.json | 2 +- .../reflectionhint/generated/reflect-config.json | 2 +- .../test/resources/reflectionhint/source/Response.java | 2 +- 17 files changed, 27 insertions(+), 27 deletions(-) diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/InitializationHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/InitializationHintProcessorTests.java index 83eb2a6..5b06578 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/InitializationHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/InitializationHintProcessorTests.java @@ -23,7 +23,7 @@ void initializationHintBuildAndRuntime() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/native-image.properties") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("initializationhint/generated/native-image-build-runtime.properties")); } @@ -37,7 +37,7 @@ void initializationHintBuild() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/native-image.properties") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("initializationhint/generated/native-image-build.properties")); } @@ -51,7 +51,7 @@ void initializationHintEntrypointAndBuildAndRuntime() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/native-image.properties") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString( "initializationhint/generated/native-image-entrypoint-build-runtime.properties")); diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/JniHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/JniHintProcessorTests.java index 04e3e75..70e0539 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/JniHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/JniHintProcessorTests.java @@ -23,7 +23,7 @@ void jniHintSelf() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/jni-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/jni-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("jnihint/generated/jni-config-only.json")); } @@ -37,7 +37,7 @@ void jniHintForMultipleAnnotations() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/jni-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/jni-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("jnihint/generated/jni-config.json")); } @@ -52,7 +52,7 @@ void jniHintForMultipleClassesAndMultipleAnnotations() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/jni-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/jni-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("jnihint/generated/jni-config-many.json")); } @@ -66,7 +66,7 @@ void jniHintForMultipleAccessHints() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/jni-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/jni-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("jnihint/generated/jni-config-only-many-access.json")); } diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessorTests.java index 41af569..cd53f2a 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessorTests.java @@ -23,7 +23,7 @@ void nativeImageHintEntrypoint() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/native-image.properties") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("nativeimagehint/generated/native-image-only.properties")); } @@ -38,7 +38,7 @@ void nativeImageHintMultipleClassesMultipleAnnotations() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/native-image.properties") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("nativeimagehint/generated/native-image.properties")); } diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessorTests.java index 8866747..d325d08 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessorTests.java @@ -23,7 +23,7 @@ void reflectionHintSelf() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/reflect-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/reflect-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("reflectionhint/generated/reflect-config-only.json")); } @@ -37,7 +37,7 @@ void reflectionHintForMultipleAnnotations() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/reflect-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/reflect-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("reflectionhint/generated/reflect-config.json")); } @@ -52,7 +52,7 @@ void reflectionHintForMultipleClassesAndMultipleAnnotations() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/reflect-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/reflect-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("reflectionhint/generated/reflect-config-many.json")); } @@ -66,7 +66,7 @@ void reflectionHintForMultipleAccessHints() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/reflect-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/reflect-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("reflectionhint/generated/reflect-config-only-many-access.json")); } diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java index 7c4b478..dff5f76 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java @@ -23,7 +23,7 @@ void resourceHintForClass() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/resource-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-single.json")); } @@ -38,7 +38,7 @@ void resourceHintForMultipleClasses() { CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint/processor/resource-config.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config.json")); } diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build-runtime.properties b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build-runtime.properties index aece02a..4627626 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build-runtime.properties +++ b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build-runtime.properties @@ -1,2 +1,2 @@ -Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOptions.class \ +Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build.properties b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build.properties index 312f9ec..5745dda 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build.properties +++ b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-build.properties @@ -1 +1 @@ -Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOptions.class +Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties index 5074ca4..fc45875 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties +++ b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties @@ -1,4 +1,4 @@ Args = -H:Name=myapp -H:Class=io.goodforgod.graalvm.hint.processor.EntrypointAndBuildAndRuntime \ -H:+PrintClassInitialization \ - --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOptions.class \ + --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/source/Build.java b/graalvm-hint-processor/src/test/resources/initializationhint/source/Build.java index a9d45aa..c02be3d 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/source/Build.java +++ b/graalvm-hint-processor/src/test/resources/initializationhint/source/Build.java @@ -3,7 +3,7 @@ import io.goodforgod.graalvm.hint.annotation.InitializationHint; import io.goodforgod.graalvm.hint.annotation.NativeImageHint; -@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOptions.class) +@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOrigin.class) public class Build { } diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/source/BuildAndRuntime.java b/graalvm-hint-processor/src/test/resources/initializationhint/source/BuildAndRuntime.java index d806c0f..fcc547f 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/source/BuildAndRuntime.java +++ b/graalvm-hint-processor/src/test/resources/initializationhint/source/BuildAndRuntime.java @@ -3,7 +3,7 @@ import io.goodforgod.graalvm.hint.annotation.InitializationHint; import io.goodforgod.graalvm.hint.annotation.NativeImageHint; -@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOptions.class) +@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOrigin.class) @InitializationHint(value = InitializationHint.InitPhase.RUNTIME, typeNames = "io.goodforgod.graalvm.hint.processor") public class BuildAndRuntime { diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/source/EntrypointAndBuildAndRuntime.java b/graalvm-hint-processor/src/test/resources/initializationhint/source/EntrypointAndBuildAndRuntime.java index 905a44e..cf29c42 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/source/EntrypointAndBuildAndRuntime.java +++ b/graalvm-hint-processor/src/test/resources/initializationhint/source/EntrypointAndBuildAndRuntime.java @@ -5,7 +5,7 @@ import io.goodforgod.graalvm.hint.annotation.NativeImageOptions; @NativeImageHint(entrypoint = EntrypointAndBuildAndRuntime.class, name = "myapp", options = NativeImageOptions.PRINT_INITIALIZATION) -@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOptions.class) +@InitializationHint(value = InitializationHint.InitPhase.BUILD, types = HintOrigin.class) @InitializationHint(value = InitializationHint.InitPhase.RUNTIME, typeNames = "io.goodforgod.graalvm.hint.processor") public class EntrypointAndBuildAndRuntime { diff --git a/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config-many.json b/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config-many.json index 19728be..5dfc0c1 100644 --- a/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config-many.json +++ b/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config-many.json @@ -3,7 +3,7 @@ "allPublicMethods": true }, { - "name": "io.goodforgod.graalvm.hint.processor.HintOptions", + "name": "io.goodforgod.graalvm.hint.processor.HintOrigin", "allDeclaredFields": true }, { diff --git a/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config.json b/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config.json index 19e2d49..80d972b 100644 --- a/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config.json +++ b/graalvm-hint-processor/src/test/resources/jnihint/generated/jni-config.json @@ -3,7 +3,7 @@ "allPublicMethods": true }, { - "name": "io.goodforgod.graalvm.hint.processor.HintOptions", + "name": "io.goodforgod.graalvm.hint.processor.HintOrigin", "allDeclaredFields": true }, { diff --git a/graalvm-hint-processor/src/test/resources/jnihint/source/Response.java b/graalvm-hint-processor/src/test/resources/jnihint/source/Response.java index 4a86602..51713b9 100644 --- a/graalvm-hint-processor/src/test/resources/jnihint/source/Response.java +++ b/graalvm-hint-processor/src/test/resources/jnihint/source/Response.java @@ -3,7 +3,7 @@ import io.goodforgod.graalvm.hint.annotation.JniHint; @JniHint(value = JniHint.AccessType.ALL_DECLARED) -@JniHint(value = JniHint.AccessType.ALL_DECLARED_FIELDS, types = HintOptions.class) +@JniHint(value = JniHint.AccessType.ALL_DECLARED_FIELDS, types = HintOrigin.class) @JniHint(value = JniHint.AccessType.ALL_PUBLIC_METHODS, typeNames = "io.goodforgod.graalvm.hint.processor") public class Response { diff --git a/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config-many.json b/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config-many.json index 19728be..5dfc0c1 100644 --- a/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config-many.json +++ b/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config-many.json @@ -3,7 +3,7 @@ "allPublicMethods": true }, { - "name": "io.goodforgod.graalvm.hint.processor.HintOptions", + "name": "io.goodforgod.graalvm.hint.processor.HintOrigin", "allDeclaredFields": true }, { diff --git a/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config.json b/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config.json index 19e2d49..80d972b 100644 --- a/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config.json +++ b/graalvm-hint-processor/src/test/resources/reflectionhint/generated/reflect-config.json @@ -3,7 +3,7 @@ "allPublicMethods": true }, { - "name": "io.goodforgod.graalvm.hint.processor.HintOptions", + "name": "io.goodforgod.graalvm.hint.processor.HintOrigin", "allDeclaredFields": true }, { diff --git a/graalvm-hint-processor/src/test/resources/reflectionhint/source/Response.java b/graalvm-hint-processor/src/test/resources/reflectionhint/source/Response.java index 7dc46a5..2fd06b7 100644 --- a/graalvm-hint-processor/src/test/resources/reflectionhint/source/Response.java +++ b/graalvm-hint-processor/src/test/resources/reflectionhint/source/Response.java @@ -3,7 +3,7 @@ import io.goodforgod.graalvm.hint.annotation.ReflectionHint; @ReflectionHint(value = ReflectionHint.AccessType.ALL_DECLARED) -@ReflectionHint(value = ReflectionHint.AccessType.ALL_DECLARED_FIELDS, types = HintOptions.class) +@ReflectionHint(value = ReflectionHint.AccessType.ALL_DECLARED_FIELDS, types = HintOrigin.class) @ReflectionHint(value = ReflectionHint.AccessType.ALL_PUBLIC_METHODS, typeNames = "io.goodforgod.graalvm.hint.processor") public class Response { From b1711000de03bfc70127f303c848cb69d7100f2f Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Fri, 8 Apr 2022 02:56:07 +0300 Subject: [PATCH 05/20] [0.18.0-SNAPSHOT] DynamicProxyHintParser added and integrated into NativeImageHintProcessor NativeImageHintProcessor refactored to be easily extendable --- .../processor/DynamicProxyHintParser.java | 107 +++++++++++ .../processor/NativeImageHintProcessor.java | 172 +++--------------- 2 files changed, 131 insertions(+), 148 deletions(-) create mode 100644 graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java new file mode 100644 index 0000000..e083d98 --- /dev/null +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java @@ -0,0 +1,107 @@ +package io.goodforgod.graalvm.hint.processor; + +import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getHintOrigin; + +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; +import java.util.*; +import java.util.stream.Collectors; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.ElementFilter; + +/** + * Processes {@link DynamicProxyHint} annotations for native-image.properties file + * + * @author Anton Kurako (GoodforGod) + * @see DynamicProxyHint + * @author Anton Kurako (GoodforGod) + * @since 07.04.2022 + */ +final class DynamicProxyHintParser implements OptionParser { + + static class Configuration { + + private final List interfaces; + + private Configuration(List interfaces) { + this.interfaces = interfaces; + } + + public List getInterfaces() { + return interfaces; + } + } + + @Override + public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { + final Set annotated = roundEnv.getElementsAnnotatedWith(DynamicProxyHint.class); + final Set elements = ElementFilter.typesIn(annotated); + + final List resources = elements.stream() + .map(element -> element.getAnnotation(DynamicProxyHint.class)) + .flatMap(hint -> Arrays.stream(hint.resources())) + .collect(Collectors.toList()); + + final List files = elements.stream() + .map(element -> element.getAnnotation(DynamicProxyHint.class)) + .flatMap(hint -> Arrays.stream(hint.files())) + .collect(Collectors.toList()); + + final List configurations = elements.stream() + .map(this::getDynamicProxyConfigurations) + .flatMap(Collection::stream) + .filter(c -> !c.getInterfaces().isEmpty()) + .collect(Collectors.toList()); + + if (!configurations.isEmpty()) { + final String proxyConfigurationFile = configurations.stream() + .map(c -> c.getInterfaces().stream() + .collect(Collectors.joining("\", \"", " { \"interfaces\": [ \"", "\" ] }"))) + .collect(Collectors.joining(",\n", "[\n", "\n]")); + + final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final String filePath = origin.getRelativePathForFile("dynamic-proxy-hint.json"); + AbstractHintProcessor.writeConfigFile(filePath, proxyConfigurationFile, processingEnv); + resources.add(filePath); + } + + final List options = new ArrayList<>(); + if (!files.isEmpty()) { + final String proxyFileOption = files.stream() + .collect(Collectors.joining(",", "-H:DynamicProxyConfigurationFiles=", "")); + options.add(proxyFileOption); + } + + if (!resources.isEmpty()) { + final String proxyResourceOption = resources.stream() + .collect(Collectors.joining(",", "-H:DynamicProxyConfigurationResources=", "")); + options.add(proxyResourceOption); + } + + return options; + } + + private List getDynamicProxyConfigurations(TypeElement element) { + final String annotationName = DynamicProxyHint.Configuration.class.getSimpleName(); + final String annotationParent = DynamicProxyHint.class.getSimpleName(); + final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, "interfaces"); + final List configurations = element.getAnnotationMirrors().stream() + .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationParent)) + .flatMap(a -> a.getElementValues().entrySet().stream() + .filter(e -> e.getKey().getSimpleName().contentEquals("value")) + .flatMap(e -> ((List) e.getValue().getValue()).stream() + .map(an -> { + final List interfaces = ((AnnotationValue) an).accept(visitor, "").stream() + .map(c -> c.substring(0, c.length() - 6)) + .collect(Collectors.toList()); + + return new Configuration(interfaces); + }))) + .collect(Collectors.toList()); + + return configurations; + } +} diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java index e73cc01..b0d2183 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java @@ -3,84 +3,46 @@ import io.goodforgod.graalvm.hint.annotation.*; import java.util.*; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedOptions; -import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; -import javax.lang.model.util.ElementFilter; import javax.tools.Diagnostic; /** - * Processes {@link NativeImageHint} and {@link InitializationHint} annotations for + * Processes {@link NativeImageHint} and {@link InitializationHint} and {@link DynamicProxyHint} + * annotations for * native-image.properties file * * @author Anton Kurako (GoodforGod) + * @see DynamicProxyHint * @see NativeImageHint * @see InitializationHint * @since 30.09.2021 */ @SupportedAnnotationTypes({ + "io.goodforgod.graalvm.hint.annotation.DynamicProxyHint", "io.goodforgod.graalvm.hint.annotation.NativeImageHint", "io.goodforgod.graalvm.hint.annotation.InitializationHint", "io.goodforgod.graalvm.hint.annotation.InitializationHints" }) @SupportedOptions({ - HintOptions.HINT_PROCESSING_GROUP, - HintOptions.HINT_PROCESSING_ARTIFACT + HintOrigin.HINT_PROCESSING_GROUP, + HintOrigin.HINT_PROCESSING_ARTIFACT }) public final class NativeImageHintProcessor extends AbstractHintProcessor { - private static final String ENTRY_POINT_DEFAULT_VALUE = Void.class.getSimpleName(); private static final String FILE_NAME = "native-image.properties"; - - private static final String INIT_BUILD_TIME = "--initialize-at-build-time="; - private static final String INIT_RUNTIME_TIME = "--initialize-at-run-time="; - private static final String ARG_SEPARATOR = " \\\n "; - static class Entrypoint { - - private final String className; - private final NativeImageHint hint; - - private Entrypoint(String className, NativeImageHint hint) { - this.className = className; - this.hint = hint; - } - } - - static class Initialization implements Comparable { + private static final NativeImageHintParser NATIVE_IMAGE_HINT_PARSER = new NativeImageHintParser(); + private static final InitializationHintParser INITIALIZATION_HINT_PARSER = new InitializationHintParser(); + private static final DynamicProxyHintParser DYNAMIC_PROXY_HINT_PARSER = new DynamicProxyHintParser(); - private final InitializationHint.InitPhase phase; - private final String className; - - Initialization(InitializationHint.InitPhase phase, String className) { - this.phase = phase; - this.className = className; - } - - @Override - public int compareTo(Initialization o) { - return className.compareTo(o.className); - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Initialization that = (Initialization) o; - return Objects.equals(className, that.className); - } - - @Override - public int hashCode() { - return Objects.hash(className); - } - } + private static final List OPTION_PARSERS = List.of( + NATIVE_IMAGE_HINT_PARSER, + INITIALIZATION_HINT_PARSER, + DYNAMIC_PROXY_HINT_PARSER); @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { @@ -89,111 +51,25 @@ public boolean process(Set annotations, RoundEnvironment } try { - final Set annotatedNative = roundEnv.getElementsAnnotatedWith(NativeImageHint.class); - final Set typesNative = ElementFilter.typesIn(annotatedNative); - final List nativeImageHintOptions = getNativeImageHintProperties(typesNative); - - final Set typesInits = getAnnotatedElements(roundEnv, InitializationHint.class, - InitializationHints.class); - final List initializationHintOptions = getInitializationHintProperties(typesInits); - - final String nativeImageProperties = Stream.of(nativeImageHintOptions, initializationHintOptions) - .flatMap(Collection::stream) - .collect(Collectors.joining(ARG_SEPARATOR, "Args = ", "")); + final List options = OPTION_PARSERS.stream() + .flatMap(parser -> parser.getOptions(roundEnv, processingEnv).stream()) + .collect(Collectors.toList()); - if (nativeImageProperties.isEmpty() && initializationHintOptions.isEmpty()) { + if (options.isEmpty()) { processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, - typesNative.size() + " annotations @NativeImageHint are present but not Options or Entrypoint found!"); + "@NativeImageHint are present but no options found"); return false; } else { - return writeConfigFile(FILE_NAME, nativeImageProperties, roundEnv); + final String nativeImageProperties = options.stream() + .collect(Collectors.joining(ARG_SEPARATOR, "Args = ", "")); + + final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final String filePath = origin.getRelativePathForFile(FILE_NAME); + return writeConfigFile(filePath, nativeImageProperties, processingEnv); } } catch (Exception e) { e.printStackTrace(); return false; } } - - private List getNativeImageHintProperties(Set elements) { - final List entrypoints = elements.stream() - .map(t -> getAnnotationFieldClassNameAny(t, NativeImageHint.class, "entrypoint") - .filter(name -> !ENTRY_POINT_DEFAULT_VALUE.equals(name)) - .map(name -> new Entrypoint(name, t.getAnnotation(NativeImageHint.class))) - .orElse(null)) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - if (entrypoints.size() > 1) { - throw new IllegalStateException("@NativeImageHint multiple entrypoint detected with values: " + entrypoints); - } - - final Optional entryClassName = entrypoints.stream().findFirst(); - final List options = elements.stream() - .map(element -> element.getAnnotation(NativeImageHint.class)) - .flatMap(hint -> Stream - .concat(Arrays.stream(hint.options()).map(NativeImageOptions::option), Arrays.stream(hint.optionNames())) - .distinct()) - .collect(Collectors.toList()); - - return entryClassName - .map(entry -> { - final List entryOptions = getEntrypointOptions(entry); - return Stream.of(entryOptions, options) - .flatMap(Collection::stream) - .distinct() - .collect(Collectors.toList()); - }) - .orElse(options); - } - - private List getEntrypointOptions(Entrypoint entrypoint) { - return (entrypoint.hint.name().isBlank()) - ? List.of("-H:Class=" + entrypoint.className) - : List.of("-H:Name=" + entrypoint.hint.name() + " -H:Class=" + entrypoint.className); - } - - private List getInitializationHintProperties(Set elements) { - final Map> groupedInitializationOptions = elements.stream() - .flatMap(e -> { - final InitializationHints hints = e.getAnnotation(InitializationHints.class); - if (hints == null) { - final InitializationHint hint = e.getAnnotation(InitializationHint.class); - return getInitialization(e, hint, false); - } else { - return Arrays.stream(hints.value()) - .flatMap(h -> getInitialization(e, h, true)); - } - }) - .distinct() - .collect(Collectors.groupingBy(e -> e.phase)); - - return groupedInitializationOptions.entrySet().stream() - .map(e -> e.getValue().stream() - .sorted() - .map(i -> i.className) - .collect(Collectors.joining(",", getInitializationArgumentName(e.getKey()), ""))) - .sorted() - .collect(Collectors.toList()); - } - - private Stream getInitialization(TypeElement element, InitializationHint hint, boolean isParentAnnotation) { - final List types = (isParentAnnotation) - ? getAnnotationFieldClassNames(element, InitializationHint.class, "types", InitializationHints.class) - : getAnnotationFieldClassNames(element, InitializationHint.class, "types"); - - final List typeNames = Arrays.asList(hint.typeNames()); - if (types.isEmpty() && typeNames.isEmpty()) { - return Stream.of(new Initialization(hint.value(), element.getQualifiedName().toString())); - } else { - return Stream.of(types, typeNames) - .flatMap(Collection::stream) - .map(type -> new Initialization(hint.value(), type)); - } - } - - private String getInitializationArgumentName(InitializationHint.InitPhase phase) { - return (InitializationHint.InitPhase.BUILD.equals(phase)) - ? INIT_BUILD_TIME - : INIT_RUNTIME_TIME; - } } From 3a2759d2a537d1237f2a38d7570b05fdbe67999f Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Fri, 8 Apr 2022 02:56:33 +0300 Subject: [PATCH 06/20] [0.18.0-SNAPSHOT] DynamicProxyHintProcessorTests added --- .../DynamicProxyHintProcessorTests.java | 79 +++++++++++++++++++ .../generated/dynamic-proxy-hint-config.json | 4 + ...ynamic-proxy-hint-resource-and-config.json | 4 + .../generated/native-image-config.properties | 1 + ...ative-image-resource-and-config.properties | 2 + .../native-image-resource.properties | 2 + .../dynamicproxyhint/source/Config.java | 11 +++ .../dynamicproxyhint/source/Resource.java | 8 ++ .../source/ResourceAndConfig.java | 13 +++ 9 files changed, 124 insertions(+) create mode 100644 graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-config.json create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-resource-and-config.json create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource.properties create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Config.java create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Resource.java create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/ResourceAndConfig.java diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java new file mode 100644 index 0000000..3cdfb47 --- /dev/null +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java @@ -0,0 +1,79 @@ +package io.goodforgod.graalvm.hint.processor; + +import com.google.testing.compile.Compilation; +import com.google.testing.compile.CompilationSubject; +import com.google.testing.compile.Compiler; +import com.google.testing.compile.JavaFileObjects; +import java.nio.charset.StandardCharsets; +import javax.tools.StandardLocation; +import org.junit.jupiter.api.Test; + +/** + * @author Anton Kurako (GoodforGod) + * @since 25.10.2021 + */ +class DynamicProxyHintProcessorTests extends ProcessorRunner { + + @Test + void configHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new NativeImageHintProcessor()) + .compile(JavaFileObjects.forResource("dynamicproxyhint/source/Config.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-config.properties")); + + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-hint.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/dynamic-proxy-hint-config.json")); + } + + @Test + void resourceHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new NativeImageHintProcessor()) + .compile(JavaFileObjects.forResource("dynamicproxyhint/source/Resource.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-resource.properties")); + } + + @Test + void resourceAndConfigHintSingleFile() { + final Compilation compilation = Compiler.javac() + .withProcessors(new NativeImageHintProcessor()) + .compile(JavaFileObjects.forResource("dynamicproxyhint/source/ResourceAndConfig.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-resource-and-config.properties")); + } + + @Test + void resourceAndConfigHintSeparateFiles() { + final Compilation compilation = Compiler.javac() + .withProcessors(new NativeImageHintProcessor()) + .compile(JavaFileObjects.forResource("dynamicproxyhint/source/Resource.java"), + JavaFileObjects.forResource("dynamicproxyhint/source/Config.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-resource-and-config.properties")); + } +} diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-config.json b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-config.json new file mode 100644 index 0000000..7b5c1f6 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-config.json @@ -0,0 +1,4 @@ +[ + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.OptionParser", "io.goodforgod.graalvm.hint.processor.HintOrigin" ] }, + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.HintOrigin" ] } +] \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-resource-and-config.json b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-resource-and-config.json new file mode 100644 index 0000000..7b5c1f6 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-resource-and-config.json @@ -0,0 +1,4 @@ +[ + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.OptionParser", "io.goodforgod.graalvm.hint.processor.HintOrigin" ] }, + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.HintOrigin" ] } +] \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties new file mode 100644 index 0000000..fa505aa --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties @@ -0,0 +1 @@ +Args = -H:DynamicProxyConfigurationResources=META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-hint.json diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties new file mode 100644 index 0000000..3061b30 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties @@ -0,0 +1,2 @@ +Args = -H:DynamicProxyConfigurationFiles=file1 \ + -H:DynamicProxyConfigurationResources=res1,res2,META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-hint.json diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource.properties b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource.properties new file mode 100644 index 0000000..351a1c8 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource.properties @@ -0,0 +1,2 @@ +Args = -H:DynamicProxyConfigurationFiles=file1 \ + -H:DynamicProxyConfigurationResources=res1,res2 diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Config.java b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Config.java new file mode 100644 index 0000000..d5bcb40 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Config.java @@ -0,0 +1,11 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; + +@DynamicProxyHint(value = { + @DynamicProxyHint.Configuration(interfaces = {OptionParser.class, HintOrigin.class}), + @DynamicProxyHint.Configuration(interfaces = {HintOrigin.class}) +}) +public class Config { + +} diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Resource.java b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Resource.java new file mode 100644 index 0000000..042fbb3 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Resource.java @@ -0,0 +1,8 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; + +@DynamicProxyHint(resources = {"res1", "res2"}, files = {"file1"}) +public class Resource { + +} diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/ResourceAndConfig.java b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/ResourceAndConfig.java new file mode 100644 index 0000000..bd6ef9c --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/ResourceAndConfig.java @@ -0,0 +1,13 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; + +@DynamicProxyHint(resources = {"res1", "res2"}, + files = {"file1"}, + value = { + @DynamicProxyHint.Configuration(interfaces = {OptionParser.class, HintOrigin.class}), + @DynamicProxyHint.Configuration(interfaces = {HintOrigin.class}) + }) +public class ResourceAndConfig { + +} From aee7717e51e64a03127e28374aa0b0bc8c63c8df Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sat, 9 Apr 2022 12:18:52 +0300 Subject: [PATCH 07/20] [0.18.0-SNAPSHOT] DynamicProxyHint javadoc added --- .../graalvm/hint/annotation/DynamicProxyHint.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java index 58380c4..f2b9df0 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java @@ -6,6 +6,10 @@ import java.lang.annotation.Target; /** + * Java dynamic proxies, implemented by java.lang.reflect.Proxy, provide a mechanism which enables + * object level access control by routing all method invocations through + * java.lang.reflect.InvocationHandler + * * @see GraalVM * Info * @author Anton Kurako (GoodforGod) @@ -25,9 +29,20 @@ Class[] interfaces() default {}; } + /** + * @see GraalVM + * @return Manual configurations for Dynamic proxy + */ Configuration[] value() default {}; + /** + * @return file configs to include under DynamicProxyConfigurationFiles option + */ String[] files() default {}; + /** + * @return resources configs to include under DynamicProxyConfigurationResources option + */ String[] resources() default {}; } From 49a94dc489c1805a41d0993465d9caf4572b4fad Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sat, 9 Apr 2022 12:19:26 +0300 Subject: [PATCH 08/20] [0.18.0-SNAPSHOT] DynamicProxyHintParser dynamic config file name changed Tests updated and reinforced --- .../hint/processor/DynamicProxyHintParser.java | 2 +- .../processor/DynamicProxyHintProcessorTests.java | 14 +++++++++++++- .../generated/native-image-config.properties | 2 +- .../native-image-resource-and-config.properties | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java index e083d98..7f4e7aa 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java @@ -63,7 +63,7 @@ public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment .collect(Collectors.joining(",\n", "[\n", "\n]")); final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); - final String filePath = origin.getRelativePathForFile("dynamic-proxy-hint.json"); + final String filePath = origin.getRelativePathForFile("dynamic-proxy-config.json"); AbstractHintProcessor.writeConfigFile(filePath, proxyConfigurationFile, processingEnv); resources.add(filePath); } diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java index 3cdfb47..b4b66a3 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java @@ -29,7 +29,7 @@ void configHint() { CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, - "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-hint.json") + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/dynamic-proxy-hint-config.json")); } @@ -60,6 +60,12 @@ void resourceAndConfigHintSingleFile() { "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-resource-and-config.properties")); + + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/dynamic-proxy-hint-resource-and-config.json")); } @Test @@ -75,5 +81,11 @@ void resourceAndConfigHintSeparateFiles() { "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") .contentsAsString(StandardCharsets.UTF_8) .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-resource-and-config.properties")); + + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/dynamic-proxy-hint-resource-and-config.json")); } } diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties index fa505aa..c58892b 100644 --- a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-config.properties @@ -1 +1 @@ -Args = -H:DynamicProxyConfigurationResources=META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-hint.json +Args = -H:DynamicProxyConfigurationResources=META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties index 3061b30..2b3b53a 100644 --- a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/native-image-resource-and-config.properties @@ -1,2 +1,2 @@ Args = -H:DynamicProxyConfigurationFiles=file1 \ - -H:DynamicProxyConfigurationResources=res1,res2,META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-hint.json + -H:DynamicProxyConfigurationResources=res1,res2,META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json From ad28bfece2b182a4a8d3dd20759b63d9c3be7dd9 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sat, 9 Apr 2022 12:49:36 +0300 Subject: [PATCH 09/20] [0.18.0-SNAPSHOT] Processors annotation based config replaced with method config HintException support added to NativeImageHintProcessor --- .../hint/processor/AbstractHintProcessor.java | 14 +++++++ .../graalvm/hint/processor/HintException.java | 14 +++++++ .../processor/NativeImageHintProcessor.java | 39 +++++++++++-------- .../processor/ReflectionHintProcessor.java | 18 ++++----- .../hint/processor/ResourceHintProcessor.java | 11 +++--- 5 files changed, 65 insertions(+), 31 deletions(-) create mode 100644 graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintException.java diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java index f4eaee8..b345ce9 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java @@ -25,6 +25,20 @@ abstract class AbstractHintProcessor extends AbstractProcessor { private static final String DEFAULT_PACKAGE = "io.graalvm.hint"; private static final String DEFAULT_ARTIFACT = "hint"; + protected abstract Set> getSupportedAnnotations(); + + @Override + public Set getSupportedAnnotationTypes() { + return getSupportedAnnotations().stream() + .map(Class::getName) + .collect(Collectors.toSet()); + } + + @Override + public Set getSupportedOptions() { + return Set.of(HintOrigin.HINT_PROCESSING_GROUP, HintOrigin.HINT_PROCESSING_ARTIFACT); + } + @Override public SourceVersion getSupportedSourceVersion() { SourceVersion sourceVersion = SourceVersion.latest(); diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintException.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintException.java new file mode 100644 index 0000000..9cba222 --- /dev/null +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintException.java @@ -0,0 +1,14 @@ +package io.goodforgod.graalvm.hint.processor; + +/** + * Manageable annotation exception + * + * @author Anton Kurako (GoodforGod) + * @since 09.04.2022 + */ +final class HintException extends RuntimeException { + + HintException(String message) { + super(message); + } +} diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java index b0d2183..5b7e975 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java @@ -1,11 +1,10 @@ package io.goodforgod.graalvm.hint.processor; import io.goodforgod.graalvm.hint.annotation.*; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedOptions; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; @@ -20,16 +19,6 @@ * @see InitializationHint * @since 30.09.2021 */ -@SupportedAnnotationTypes({ - "io.goodforgod.graalvm.hint.annotation.DynamicProxyHint", - "io.goodforgod.graalvm.hint.annotation.NativeImageHint", - "io.goodforgod.graalvm.hint.annotation.InitializationHint", - "io.goodforgod.graalvm.hint.annotation.InitializationHints" -}) -@SupportedOptions({ - HintOrigin.HINT_PROCESSING_GROUP, - HintOrigin.HINT_PROCESSING_ARTIFACT -}) public final class NativeImageHintProcessor extends AbstractHintProcessor { private static final String FILE_NAME = "native-image.properties"; @@ -45,8 +34,17 @@ public final class NativeImageHintProcessor extends AbstractHintProcessor { DYNAMIC_PROXY_HINT_PARSER); @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - if (annotations.isEmpty()) { + protected Set> getSupportedAnnotations() { + return Set.of( + DynamicProxyHint.class, + NativeImageHint.class, + InitializationHint.class, + InitializationHints.class); + } + + @Override + public boolean process(Set annotatedElements, RoundEnvironment roundEnv) { + if (annotatedElements.isEmpty()) { return false; } @@ -56,8 +54,14 @@ public boolean process(Set annotations, RoundEnvironment .collect(Collectors.toList()); if (options.isEmpty()) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, - "@NativeImageHint are present but no options found"); + final String annotations = OPTION_PARSERS.stream() + .flatMap(p -> p.annotations().stream() + .filter(a -> !roundEnv.getElementsAnnotatedWith(a).isEmpty())) + .map(Class::getSimpleName) + .collect(Collectors.joining(",")); + + processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, + annotations + " are present but no options retrieved"); return false; } else { final String nativeImageProperties = options.stream() @@ -67,6 +71,9 @@ public boolean process(Set annotations, RoundEnvironment final String filePath = origin.getRelativePathForFile(FILE_NAME); return writeConfigFile(filePath, nativeImageProperties, processingEnv); } + } catch (HintException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); + return false; } catch (Exception e) { e.printStackTrace(); return false; diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java index bda3dce..75f783f 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java @@ -3,12 +3,11 @@ import io.goodforgod.graalvm.hint.annotation.ReflectionHint; import io.goodforgod.graalvm.hint.annotation.ReflectionHint.AccessType; import io.goodforgod.graalvm.hint.annotation.ReflectionHints; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedOptions; import javax.lang.model.element.TypeElement; /** @@ -18,16 +17,15 @@ * @see ReflectionHint * @since 27.09.2021 */ -@SupportedAnnotationTypes({ - "io.goodforgod.graalvm.hint.annotation.ReflectionHint", - "io.goodforgod.graalvm.hint.annotation.ReflectionHints" -}) -@SupportedOptions({ - HintOrigin.HINT_PROCESSING_GROUP, - HintOrigin.HINT_PROCESSING_ARTIFACT -}) public final class ReflectionHintProcessor extends AbstractAccessHintProcessor { + @Override + protected Set> getSupportedAnnotations() { + return Set.of( + ReflectionHint.class, + ReflectionHints.class); + } + @Override protected String getFileName() { return "reflect-config.json"; diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java index f9c3e9f..eb6ad45 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java @@ -1,6 +1,7 @@ package io.goodforgod.graalvm.hint.processor; import io.goodforgod.graalvm.hint.annotation.ResourceHint; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import javax.annotation.processing.*; @@ -16,16 +17,16 @@ * @see ResourceHint * @since 27.09.2021 */ -@SupportedAnnotationTypes("io.goodforgod.graalvm.hint.annotation.ResourceHint") -@SupportedOptions({ - HintOrigin.HINT_PROCESSING_GROUP, - HintOrigin.HINT_PROCESSING_ARTIFACT -}) public final class ResourceHintProcessor extends AbstractHintProcessor { private static final String FILE_NAME = "resource-config.json"; private static final String PATTERN = "pattern"; + @Override + protected Set> getSupportedAnnotations() { + return Set.of(ResourceHint.class); + } + @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (annotations.isEmpty()) { From 287a884755b2caff8c7040c67c0307b2f2227218 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sat, 9 Apr 2022 12:50:51 +0300 Subject: [PATCH 10/20] [0.18.0-SNAPSHOT] OptionParser#annotations contract added to extract processable parsers annotations to form exception message --- .../processor/InitializationHintParser.java | 6 ++++++ .../hint/processor/JniHintProcessor.java | 18 ++++++++---------- .../hint/processor/NativeImageHintParser.java | 6 ++++++ .../graalvm/hint/processor/OptionParser.java | 3 +++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java index 1556aeb..5e5b863 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java @@ -5,6 +5,7 @@ import io.goodforgod.graalvm.hint.annotation.InitializationHint; import io.goodforgod.graalvm.hint.annotation.InitializationHints; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -56,6 +57,11 @@ public int hashCode() { } } + @Override + public List> annotations() { + return List.of(InitializationHint.class, InitializationHints.class); + } + @Override public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { final Set elements = getAnnotatedElements(roundEnv, InitializationHint.class, InitializationHints.class); diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java index ec992db..b57b182 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java @@ -3,12 +3,11 @@ import io.goodforgod.graalvm.hint.annotation.JniHint; import io.goodforgod.graalvm.hint.annotation.JniHints; import io.goodforgod.graalvm.hint.annotation.ReflectionHint; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedOptions; import javax.lang.model.element.TypeElement; /** @@ -18,20 +17,19 @@ * @author Anton Kurako (GoodforGod) * @since 21.03.2022 */ -@SupportedAnnotationTypes({ - "io.goodforgod.graalvm.hint.annotation.JniHint", - "io.goodforgod.graalvm.hint.annotation.JniHints" -}) -@SupportedOptions({ - HintOrigin.HINT_PROCESSING_GROUP, - HintOrigin.HINT_PROCESSING_ARTIFACT -}) public final class JniHintProcessor extends AbstractAccessHintProcessor { private static final Map ACCESS_TYPE_MAP = Arrays .stream(ReflectionHint.AccessType.values()) .collect(Collectors.toMap(Enum::name, e -> e)); + @Override + protected Set> getSupportedAnnotations() { + return Set.of( + JniHint.class, + JniHints.class); + } + @Override protected String getFileName() { return "jni-config.json"; diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java index c4af6a8..f430720 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java @@ -4,6 +4,7 @@ import io.goodforgod.graalvm.hint.annotation.NativeImageHint; import io.goodforgod.graalvm.hint.annotation.NativeImageOptions; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -36,6 +37,11 @@ private Entrypoint(String className, NativeImageHint hint) { } } + @Override + public List> annotations() { + return List.of(NativeImageHint.class); + } + @Override public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { final Set annotatedNative = roundEnv.getElementsAnnotatedWith(NativeImageHint.class); diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java index 1efaaaf..a75d277 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java @@ -1,5 +1,6 @@ package io.goodforgod.graalvm.hint.processor; +import java.lang.annotation.Annotation; import java.util.List; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; @@ -12,5 +13,7 @@ */ interface OptionParser { + List> annotations(); + List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv); } From 521336d86de298c20107449dc4b56ca9c2f494fb Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sun, 10 Apr 2022 02:32:23 +0300 Subject: [PATCH 11/20] [0.18.0-SNAPSHOT] NativeImageOptions added All static util methods moved out of AbstractHintProcessor to HintUtils --- .../hint/annotation/DynamicProxyHint.java | 1 - .../hint/annotation/NativeImageOptions.java | 6 +- .../AbstractAccessHintProcessor.java | 30 ++-- .../hint/processor/AbstractHintProcessor.java | 128 +--------------- .../graalvm/hint/processor/HintUtils.java | 138 ++++++++++++++++++ 5 files changed, 155 insertions(+), 148 deletions(-) create mode 100644 graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java index f2b9df0..8d85880 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java @@ -19,7 +19,6 @@ @Retention(RetentionPolicy.SOURCE) public @interface DynamicProxyHint { - @Target({ ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.SOURCE) @interface Configuration { diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/NativeImageOptions.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/NativeImageOptions.java index ff7664e..59c933b 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/NativeImageOptions.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/NativeImageOptions.java @@ -27,7 +27,11 @@ public enum NativeImageOptions { ENABLE_HTTPS("--enable-https"), ENABLE_URL_PROTOCOLS("--enable-url-protocols"), ALLOW_INCOMPLETE_CLASSPATH("--allow-incomplete-classpath"), - REPORT_UNSUPPORTED("--report-unsupported-elements-at-runtime"); + REPORT_UNSUPPORTED("--report-unsupported-elements-at-runtime"), + INCLUDE_ALL_LOCALES("-H:+IncludeAllLocales"), + LOCALISATION_OPTIMIZED_MODE("-H:-LocalizationOptimizedMode"), + LOG_REGISTERED_RESOURCE_MIN("-H:Log=registerResource:1"), + LOG_REGISTERED_RESOURCE_MAX("-H:Log=registerResource:5"); private final String option; diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java index c043763..eb41945 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractAccessHintProcessor.java @@ -10,7 +10,6 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic; /** * Processes {@link ReflectionHint} and {@link JniHint} annotations for native-image hint files @@ -65,12 +64,13 @@ public int hashCode() { protected abstract String getFileName(); - protected abstract String getEmptyConfigWarningMessage(); - - protected abstract Set getAnnotatedTypeElements(RoundEnvironment roundEnv); - protected abstract Collection getGraalAccessForAnnotatedElement(TypeElement element); + protected Set getAnnotatedTypeElements(RoundEnvironment roundEnv) { + final Class[] classes = getSupportedAnnotations().toArray(Class[]::new); + return HintUtils.getAnnotatedElements(roundEnv, classes); + } + protected Predicate getParentAnnotationPredicate(ReflectionHint.AccessType[] accessTypes) { return a -> ((AnnotationMirror) a).getElementValues().entrySet().stream() .filter(e -> e.getKey().getSimpleName().contentEquals("value")) @@ -110,29 +110,21 @@ public boolean process(Set annotations, RoundEnvironment .sorted() .collect(Collectors.toList()); - final Optional configJson = getAccessConfigJson(accesses); - if (configJson.isEmpty()) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, getEmptyConfigWarningMessage()); - return false; - } - - final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final String configJson = getAccessConfigJson(accesses); + final HintOrigin origin = HintUtils.getHintOrigin(roundEnv, processingEnv); final String filePath = origin.getRelativePathForFile(getFileName()); - return writeConfigFile(filePath, configJson.get(), processingEnv); + return HintUtils.writeConfigFile(filePath, configJson, processingEnv); } catch (Exception e) { e.printStackTrace(); return false; } } - private Optional getAccessConfigJson(Collection accesses) { - if (accesses.isEmpty()) - return Optional.empty(); - - return Optional.of(accesses.stream() + private String getAccessConfigJson(Collection accesses) { + return accesses.stream() .map(AbstractAccessHintProcessor::getGraalReflectionForTypeName) .map(AbstractAccessHintProcessor::mapToJson) - .collect(Collectors.joining(",\n", "[", "]"))); + .collect(Collectors.joining(",\n", "[", "]")); } private static String mapToJson(Map map) { diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java index b345ce9..00c3b6f 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AbstractHintProcessor.java @@ -1,20 +1,10 @@ package io.goodforgod.graalvm.hint.processor; -import java.io.Writer; import java.lang.annotation.Annotation; -import java.util.*; -import java.util.function.Predicate; +import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; import javax.lang.model.SourceVersion; -import javax.lang.model.element.*; -import javax.lang.model.util.ElementFilter; -import javax.tools.Diagnostic; -import javax.tools.FileObject; -import javax.tools.StandardLocation; /** * @author Anton Kurako (GoodforGod) @@ -22,9 +12,6 @@ */ abstract class AbstractHintProcessor extends AbstractProcessor { - private static final String DEFAULT_PACKAGE = "io.graalvm.hint"; - private static final String DEFAULT_ARTIFACT = "hint"; - protected abstract Set> getSupportedAnnotations(); @Override @@ -52,117 +39,4 @@ public SourceVersion getSupportedSourceVersion() { return SourceVersion.values()[17]; } } - - static HintOrigin getHintOrigin(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { - final Map options = processingEnv.getOptions(); - final Element anyElement = roundEnv.getRootElements().iterator().next(); - - final String group = (options.containsKey(HintOrigin.HINT_PROCESSING_GROUP)) - ? options.get(HintOrigin.HINT_PROCESSING_GROUP) - : getPackage(anyElement); - - final String artifact = (options.containsKey(HintOrigin.HINT_PROCESSING_ARTIFACT)) - ? options.get(HintOrigin.HINT_PROCESSING_ARTIFACT) - : getArtifact(anyElement); - - return new HintOrigin(group, artifact); - } - - static Set getAnnotatedElements(RoundEnvironment roundEnv, Class... annotations) { - return Arrays.stream(annotations) - .flatMap(a -> { - final Set annotated = roundEnv.getElementsAnnotatedWith(a); - if (annotated == null || annotated.isEmpty()) - return Stream.empty(); - - return ElementFilter.typesIn(annotated).stream(); - }) - .collect(Collectors.toSet()); - } - - static Optional getAnnotationFieldClassNameAny(TypeElement type, - Class annotation, - String annotationFieldName) { - final List classNames = getAnnotationFieldClassNames(type, annotation, annotationFieldName); - return classNames.isEmpty() - ? Optional.empty() - : Optional.of(classNames.get(0)); - } - - static List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName) { - final String annotationName = annotation.getSimpleName(); - final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, annotationFieldName); - return type.getAnnotationMirrors().stream() - .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationName)) - .flatMap(a -> visitor.visitAnnotation(a, "").stream()) - .collect(Collectors.toList()); - } - - static List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName, - Class parentAnnotation) { - return getAnnotationFieldClassNames(type, annotation, annotationFieldName, parentAnnotation, a -> true); - } - - static List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName, - Class parentAnnotation, - Predicate annotationPredicate) { - return getAnnotationFieldClassNames(type, annotation, annotationFieldName, parentAnnotation, annotationPredicate, - e -> e.getSimpleName().contentEquals("value")); - } - - static List getAnnotationFieldClassNames(TypeElement type, - Class annotation, - String annotationFieldName, - Class parentAnnotation, - Predicate annotationPredicate, - Predicate parentAnnotationKeyPredicate) { - final String annotationName = annotation.getSimpleName(); - final String annotationParent = parentAnnotation.getSimpleName(); - final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, annotationFieldName); - return type.getAnnotationMirrors().stream() - .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationParent)) - .flatMap(a -> a.getElementValues().entrySet().stream() - .filter(e -> parentAnnotationKeyPredicate.test(e.getKey())) - .flatMap(e -> ((List) e.getValue().getValue()).stream() - .filter(an -> annotationPredicate.test(((AnnotationValue) an))) - .flatMap(an -> ((AnnotationValue) an).accept(visitor, "").stream())) - .map(Object::toString) - .filter(e -> !e.isBlank())) - .collect(Collectors.toList()); - } - - static boolean writeConfigFile(String filePath, String data, ProcessingEnvironment processingEnv) { - try { - final FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filePath); - try (Writer writer = fileObject.openWriter()) { - writer.write(data); - } - } catch (Exception e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Couldn't write " + filePath + " due to: " + e.getMessage()); - return false; - } - - processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Generating file " + filePath + " to: " + filePath); - return true; - } - - private static String getPackage(Element element) { - final Element enclosingElement = element.getEnclosingElement(); - if (enclosingElement instanceof PackageElement) { - return ((PackageElement) enclosingElement).getQualifiedName().toString(); - } - - return DEFAULT_PACKAGE; - } - - private static String getArtifact(Element element) { - return DEFAULT_ARTIFACT; - } } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java new file mode 100644 index 0000000..0054880 --- /dev/null +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java @@ -0,0 +1,138 @@ +package io.goodforgod.graalvm.hint.processor; + +import java.io.Writer; +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.*; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +/** + * @author Anton Kurako (GoodforGod) + * @since 09.04.2022 + */ +final class HintUtils { + + private HintUtils() {} + + static HintOrigin getHintOrigin(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { + final Map options = processingEnv.getOptions(); + final Set rootElements = roundEnv.getRootElements(); + final Element anyElement = rootElements.iterator().next(); + + final String group = (options.containsKey(HintOrigin.HINT_PROCESSING_GROUP)) + ? options.get(HintOrigin.HINT_PROCESSING_GROUP) + : getPackage(anyElement); + + final String artifact = (options.containsKey(HintOrigin.HINT_PROCESSING_ARTIFACT)) + ? options.get(HintOrigin.HINT_PROCESSING_ARTIFACT) + : getArtifact(anyElement); + + return new HintOrigin(group, artifact); + } + + static Set getAnnotatedElements(RoundEnvironment roundEnv, Class... annotations) { + return Arrays.stream(annotations) + .flatMap(a -> { + final Set annotated = roundEnv.getElementsAnnotatedWith(a); + if (annotated == null || annotated.isEmpty()) + return Stream.empty(); + + return ElementFilter.typesIn(annotated).stream(); + }) + .collect(Collectors.toSet()); + } + + static Optional getAnnotationFieldClassNameAny(TypeElement type, + Class annotation, + String annotationFieldName) { + final List classNames = getAnnotationFieldClassNames(type, annotation, annotationFieldName); + return classNames.isEmpty() + ? Optional.empty() + : Optional.of(classNames.get(0)); + } + + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName) { + final String annotationName = annotation.getSimpleName(); + final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, annotationFieldName); + return type.getAnnotationMirrors().stream() + .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationName)) + .flatMap(a -> visitor.visitAnnotation(a, null).stream()) + .collect(Collectors.toList()); + } + + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName, + Class parentAnnotation) { + return getAnnotationFieldClassNames(type, annotation, annotationFieldName, parentAnnotation, a -> true); + } + + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName, + Class parentAnnotation, + Predicate annotationPredicate) { + return getAnnotationFieldClassNames(type, annotation, annotationFieldName, parentAnnotation, annotationPredicate, + e -> e.getSimpleName().contentEquals("value")); + } + + static List getAnnotationFieldClassNames(TypeElement type, + Class annotation, + String annotationFieldName, + Class parentAnnotation, + Predicate annotationPredicate, + Predicate parentAnnotationKeyPredicate) { + final String annotationName = annotation.getSimpleName(); + final String annotationParent = parentAnnotation.getSimpleName(); + final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, annotationFieldName); + return type.getAnnotationMirrors().stream() + .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationParent)) + .flatMap(a -> a.getElementValues().entrySet().stream() + .filter(e -> parentAnnotationKeyPredicate.test(e.getKey())) + .flatMap(e -> ((List) e.getValue().getValue()).stream() + .filter(an -> annotationPredicate.test(((AnnotationValue) an))) + .flatMap(an -> ((AnnotationValue) an).accept(visitor, null).stream())) + .map(Object::toString) + .filter(e -> !e.isBlank())) + .collect(Collectors.toList()); + } + + static boolean writeConfigFile(String filePath, String data, ProcessingEnvironment processingEnv) { + try { + final FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filePath); + try (Writer writer = fileObject.openWriter()) { + writer.write(data); + } + } catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Couldn't write " + filePath + " due to: " + e.getMessage()); + return false; + } + + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Generating file " + filePath + " to: " + filePath); + return true; + } + + private static String getPackage(Element element) { + final Element enclosingElement = element.getEnclosingElement(); + if (enclosingElement instanceof PackageElement) { + return ((PackageElement) enclosingElement).getQualifiedName().toString(); + } + + return HintOrigin.DEFAULT_PACKAGE; + } + + private static String getArtifact(Element element) { + return HintOrigin.DEFAULT_ARTIFACT; + } +} From 30aefaa656ee5f53b2bedbf938d17620388bea1c Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sun, 10 Apr 2022 02:34:52 +0300 Subject: [PATCH 12/20] [0.18.0-SNAPSHOT] Imports fixed NativeImageHintProcessor exception handling improved NativeImageHintProcessor order of class and app name changed NativeImageHintProcessor tests updated --- .../processor/AnnotationTypeFieldVisitor.java | 32 ++++++++-------- .../processor/DynamicProxyHintParser.java | 37 +++++++++++++++---- .../graalvm/hint/processor/HintOrigin.java | 5 ++- .../processor/InitializationHintParser.java | 10 ++--- .../hint/processor/JniHintProcessor.java | 15 +------- .../hint/processor/NativeImageHintParser.java | 28 +++++++++----- .../processor/NativeImageHintProcessor.java | 12 ++++-- .../processor/ReflectionHintProcessor.java | 20 +++------- ...-image-entrypoint-build-runtime.properties | 2 +- .../generated/native-image.properties | 2 +- 10 files changed, 90 insertions(+), 73 deletions(-) diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AnnotationTypeFieldVisitor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AnnotationTypeFieldVisitor.java index 79d6923..24804c2 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AnnotationTypeFieldVisitor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/AnnotationTypeFieldVisitor.java @@ -15,7 +15,7 @@ * @author Anton Kurako (GoodforGod) * @since 10.10.2021 */ -final class AnnotationTypeFieldVisitor implements AnnotationValueVisitor, String> { +final class AnnotationTypeFieldVisitor implements AnnotationValueVisitor, Void> { private final String annotationName; private final String annotationFieldName; @@ -26,67 +26,67 @@ final class AnnotationTypeFieldVisitor implements AnnotationValueVisitor visit(AnnotationValue av, String s) { + public List visit(AnnotationValue av, Void unused) { return Collections.emptyList(); } @Override - public List visitBoolean(boolean b, String s) { + public List visitBoolean(boolean b, Void unused) { return Collections.emptyList(); } @Override - public List visitByte(byte b, String s) { + public List visitByte(byte b, Void unused) { return Collections.emptyList(); } @Override - public List visitChar(char c, String s) { + public List visitChar(char c, Void unused) { return Collections.emptyList(); } @Override - public List visitDouble(double d, String s) { + public List visitDouble(double d, Void unused) { return Collections.emptyList(); } @Override - public List visitFloat(float f, String s) { + public List visitFloat(float f, Void unused) { return Collections.emptyList(); } @Override - public List visitInt(int i, String s) { + public List visitInt(int i, Void unused) { return Collections.emptyList(); } @Override - public List visitLong(long i, String s) { + public List visitLong(long i, Void unused) { return Collections.emptyList(); } @Override - public List visitShort(short s, String s2) { + public List visitShort(short s, Void unused) { return Collections.emptyList(); } @Override - public List visitString(String s, String s2) { + public List visitString(String s, Void unused) { return Collections.emptyList(); } @Override - public List visitType(TypeMirror t, String s) { + public List visitType(TypeMirror t, Void unused) { return Collections.emptyList(); } @Override - public List visitEnumConstant(VariableElement c, String s) { + public List visitEnumConstant(VariableElement c, Void unused) { return Collections.emptyList(); } @Override - public List visitAnnotation(AnnotationMirror a, String s) { + public List visitAnnotation(AnnotationMirror a, Void unused) { if (a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationName)) { return a.getElementValues().entrySet().stream() .filter(e -> e.getKey().getSimpleName().contentEquals(annotationFieldName)) @@ -104,12 +104,12 @@ public List visitAnnotation(AnnotationMirror a, String s) { } @Override - public List visitArray(List vals, String s) { + public List visitArray(List vals, Void unused) { return Collections.emptyList(); } @Override - public List visitUnknown(AnnotationValue av, String s) { + public List visitUnknown(AnnotationValue av, Void unused) { return Collections.emptyList(); } } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java index 7f4e7aa..fcd35e3 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java @@ -1,8 +1,7 @@ package io.goodforgod.graalvm.hint.processor; -import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getHintOrigin; - import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; +import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; import javax.annotation.processing.ProcessingEnvironment; @@ -35,6 +34,11 @@ public List getInterfaces() { } } + @Override + public List> annotations() { + return List.of(DynamicProxyHint.class); + } + @Override public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { final Set annotated = roundEnv.getElementsAnnotatedWith(DynamicProxyHint.class); @@ -62,9 +66,9 @@ public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment .collect(Collectors.joining("\", \"", " { \"interfaces\": [ \"", "\" ] }"))) .collect(Collectors.joining(",\n", "[\n", "\n]")); - final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final HintOrigin origin = HintUtils.getHintOrigin(roundEnv, processingEnv); final String filePath = origin.getRelativePathForFile("dynamic-proxy-config.json"); - AbstractHintProcessor.writeConfigFile(filePath, proxyConfigurationFile, processingEnv); + HintUtils.writeConfigFile(filePath, proxyConfigurationFile, processingEnv); resources.add(filePath); } @@ -88,13 +92,13 @@ private List getDynamicProxyConfigurations(TypeElement element) { final String annotationName = DynamicProxyHint.Configuration.class.getSimpleName(); final String annotationParent = DynamicProxyHint.class.getSimpleName(); final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, "interfaces"); - final List configurations = element.getAnnotationMirrors().stream() + final List interfaceConfigurations = element.getAnnotationMirrors().stream() .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationParent)) .flatMap(a -> a.getElementValues().entrySet().stream() .filter(e -> e.getKey().getSimpleName().contentEquals("value")) .flatMap(e -> ((List) e.getValue().getValue()).stream() .map(an -> { - final List interfaces = ((AnnotationValue) an).accept(visitor, "").stream() + final List interfaces = ((AnnotationValue) an).accept(visitor, null).stream() .map(c -> c.substring(0, c.length() - 6)) .collect(Collectors.toList()); @@ -102,6 +106,25 @@ private List getDynamicProxyConfigurations(TypeElement element) { }))) .collect(Collectors.toList()); - return configurations; + if (interfaceConfigurations.isEmpty() && isSelfConfiguration(element)) { + if (element.getKind().isInterface()) { + interfaceConfigurations.add(new Configuration(List.of(element.getQualifiedName().toString()))); + } else { + throw new HintException(element.getQualifiedName().toString() + " is annotated with @" + + DynamicProxyHint.class.getSimpleName() + " hint but is not an interface"); + } + } + + return interfaceConfigurations; + } + + private boolean isSelfConfiguration(TypeElement element) { + final DynamicProxyHint annotation = element.getAnnotation(DynamicProxyHint.class); + if (annotation == null) { + return false; + } + + return (annotation.resources() == null || annotation.resources().length == 0) + && (annotation.files() == null || annotation.files().length == 0); } } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java index 10045b6..f3e8b1f 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintOrigin.java @@ -1,7 +1,7 @@ package io.goodforgod.graalvm.hint.processor; /** - * Hint origin package and artifact + * Hint origin package and artifact where all configs will be generated * * @author Anton Kurako (GoodforGod) * @since 29.09.2021 @@ -11,6 +11,9 @@ final class HintOrigin { public static final String HINT_PROCESSING_GROUP = "graalvm.hint.group"; public static final String HINT_PROCESSING_ARTIFACT = "graalvm.hint.artifact"; + static final String DEFAULT_PACKAGE = "io.graalvm.hint"; + static final String DEFAULT_ARTIFACT = "hint"; + /** * Artifact group of project */ diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java index 5e5b863..0a01142 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java @@ -1,8 +1,5 @@ package io.goodforgod.graalvm.hint.processor; -import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getAnnotatedElements; -import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getAnnotationFieldClassNames; - import io.goodforgod.graalvm.hint.annotation.InitializationHint; import io.goodforgod.graalvm.hint.annotation.InitializationHints; import java.lang.annotation.Annotation; @@ -64,7 +61,8 @@ public List> annotations() { @Override public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { - final Set elements = getAnnotatedElements(roundEnv, InitializationHint.class, InitializationHints.class); + final Set elements = HintUtils.getAnnotatedElements(roundEnv, InitializationHint.class, + InitializationHints.class); final Map> groupedInitializationOptions = elements.stream() .flatMap(e -> { @@ -91,8 +89,8 @@ public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment private Stream getInitializations(TypeElement element, InitializationHint hint, boolean isParentAnnotation) { final List types = (isParentAnnotation) - ? getAnnotationFieldClassNames(element, InitializationHint.class, "types", InitializationHints.class) - : getAnnotationFieldClassNames(element, InitializationHint.class, "types"); + ? HintUtils.getAnnotationFieldClassNames(element, InitializationHint.class, "types", InitializationHints.class) + : HintUtils.getAnnotationFieldClassNames(element, InitializationHint.class, "types"); final List typeNames = Arrays.asList(hint.typeNames()); if (types.isEmpty() && typeNames.isEmpty()) { diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java index b57b182..49c315f 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/JniHintProcessor.java @@ -7,7 +7,6 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.TypeElement; /** @@ -35,16 +34,6 @@ protected String getFileName() { return "jni-config.json"; } - @Override - protected String getEmptyConfigWarningMessage() { - return "@JniHint annotation found, but no reflection access hints parsed"; - } - - @Override - protected Set getAnnotatedTypeElements(RoundEnvironment roundEnv) { - return getAnnotatedElements(roundEnv, JniHint.class, JniHints.class); - } - @Override protected Collection getGraalAccessForAnnotatedElement(TypeElement element) { final JniHints hints = element.getAnnotation(JniHints.class); @@ -64,8 +53,8 @@ private Collection getGraalAccessForAnnotatedElement(TypeElement element final ReflectionHint.AccessType[] accessTypes = convert(hint.value()); final List typeNames = Arrays.asList(hint.typeNames()); final List types = (!isParentAnnotation) - ? getAnnotationFieldClassNames(element, JniHint.class, "types") - : getAnnotationFieldClassNames(element, JniHint.class, "types", JniHints.class, + ? HintUtils.getAnnotationFieldClassNames(element, JniHint.class, "types") + : HintUtils.getAnnotationFieldClassNames(element, JniHint.class, "types", JniHints.class, getParentAnnotationPredicate(accessTypes)); if (types.isEmpty() && typeNames.isEmpty()) { diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java index f430720..8987c80 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java @@ -1,7 +1,5 @@ package io.goodforgod.graalvm.hint.processor; -import static io.goodforgod.graalvm.hint.processor.AbstractHintProcessor.getAnnotationFieldClassNameAny; - import io.goodforgod.graalvm.hint.annotation.NativeImageHint; import io.goodforgod.graalvm.hint.annotation.NativeImageOptions; import java.lang.annotation.Annotation; @@ -29,11 +27,20 @@ final class NativeImageHintParser implements OptionParser { private static class Entrypoint { private final String className; - private final NativeImageHint hint; + private final TypeElement source; - private Entrypoint(String className, NativeImageHint hint) { + private Entrypoint(String className, TypeElement source) { this.className = className; - this.hint = hint; + this.source = source; + } + + NativeImageHint hint() { + return source.getAnnotation(NativeImageHint.class); + } + + @Override + public String toString() { + return "entrypoint=" + className + ", source=" + source.getQualifiedName(); } } @@ -48,15 +55,15 @@ public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment final Set elements = ElementFilter.typesIn(annotatedNative); final List entrypoints = elements.stream() - .map(t -> getAnnotationFieldClassNameAny(t, NativeImageHint.class, "entrypoint") + .map(element -> HintUtils.getAnnotationFieldClassNameAny(element, NativeImageHint.class, "entrypoint") .filter(name -> !ENTRY_POINT_DEFAULT_VALUE.equals(name)) - .map(name -> new Entrypoint(name, t.getAnnotation(NativeImageHint.class))) + .map(name -> new Entrypoint(name, element)) .orElse(null)) .filter(Objects::nonNull) .collect(Collectors.toList()); if (entrypoints.size() > 1) { - throw new IllegalStateException("@NativeImageHint multiple entrypoint detected with values: " + entrypoints); + throw new HintException("@NativeImageHint multiple entrypoints detected: " + entrypoints); } final Optional entryClassName = entrypoints.stream().findFirst(); @@ -79,8 +86,9 @@ public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment } private List getEntrypointOptions(Entrypoint entrypoint) { - return (entrypoint.hint.name().isBlank()) + final String appName = entrypoint.hint().name(); + return (appName.isBlank()) ? List.of("-H:Class=" + entrypoint.className) - : List.of("-H:Name=" + entrypoint.hint.name() + " -H:Class=" + entrypoint.className); + : List.of("-H:Class=" + entrypoint.className + " -H:Name=" + appName); } } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java index 5b7e975..8d99417 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java @@ -1,8 +1,12 @@ package io.goodforgod.graalvm.hint.processor; -import io.goodforgod.graalvm.hint.annotation.*; +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; +import io.goodforgod.graalvm.hint.annotation.InitializationHint; +import io.goodforgod.graalvm.hint.annotation.InitializationHints; +import io.goodforgod.graalvm.hint.annotation.NativeImageHint; import java.lang.annotation.Annotation; -import java.util.*; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.TypeElement; @@ -67,9 +71,9 @@ public boolean process(Set annotatedElements, RoundEnviro final String nativeImageProperties = options.stream() .collect(Collectors.joining(ARG_SEPARATOR, "Args = ", "")); - final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final HintOrigin origin = HintUtils.getHintOrigin(roundEnv, processingEnv); final String filePath = origin.getRelativePathForFile(FILE_NAME); - return writeConfigFile(filePath, nativeImageProperties, processingEnv); + return HintUtils.writeConfigFile(filePath, nativeImageProperties, processingEnv); } } catch (HintException e) { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java index 75f783f..27e5f3b 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ReflectionHintProcessor.java @@ -4,10 +4,12 @@ import io.goodforgod.graalvm.hint.annotation.ReflectionHint.AccessType; import io.goodforgod.graalvm.hint.annotation.ReflectionHints; import java.lang.annotation.Annotation; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.TypeElement; /** @@ -31,16 +33,6 @@ protected String getFileName() { return "reflect-config.json"; } - @Override - protected String getEmptyConfigWarningMessage() { - return "@ReflectionHint annotation found, but no reflection access hints parsed"; - } - - @Override - protected Set getAnnotatedTypeElements(RoundEnvironment roundEnv) { - return getAnnotatedElements(roundEnv, ReflectionHint.class, ReflectionHints.class); - } - @Override protected Collection getGraalAccessForAnnotatedElement(TypeElement element) { final ReflectionHints hints = element.getAnnotation(ReflectionHints.class); @@ -60,8 +52,8 @@ private Collection getGraalAccessForAnnotatedElement(TypeElement element final AccessType[] accessTypes = hint.value(); final List typeNames = Arrays.asList(hint.typeNames()); final List types = (!isParentAnnotation) - ? getAnnotationFieldClassNames(element, ReflectionHint.class, "types") - : getAnnotationFieldClassNames(element, ReflectionHint.class, "types", ReflectionHints.class, + ? HintUtils.getAnnotationFieldClassNames(element, ReflectionHint.class, "types") + : HintUtils.getAnnotationFieldClassNames(element, ReflectionHint.class, "types", ReflectionHints.class, getParentAnnotationPredicate(accessTypes)); if (types.isEmpty() && typeNames.isEmpty()) { diff --git a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties index fc45875..0dd0e41 100644 --- a/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties +++ b/graalvm-hint-processor/src/test/resources/initializationhint/generated/native-image-entrypoint-build-runtime.properties @@ -1,4 +1,4 @@ -Args = -H:Name=myapp -H:Class=io.goodforgod.graalvm.hint.processor.EntrypointAndBuildAndRuntime \ +Args = -H:Class=io.goodforgod.graalvm.hint.processor.EntrypointAndBuildAndRuntime -H:Name=myapp \ -H:+PrintClassInitialization \ --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor diff --git a/graalvm-hint-processor/src/test/resources/nativeimagehint/generated/native-image.properties b/graalvm-hint-processor/src/test/resources/nativeimagehint/generated/native-image.properties index c552583..339f982 100644 --- a/graalvm-hint-processor/src/test/resources/nativeimagehint/generated/native-image.properties +++ b/graalvm-hint-processor/src/test/resources/nativeimagehint/generated/native-image.properties @@ -1,3 +1,3 @@ -Args = -H:Name=myapp -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint \ +Args = -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint -H:Name=myapp \ -H:+PrintClassInitialization \ -H:+InlineBeforeAnalysis From 20961b4ea645c63b4fa725d3097cb9254e712ecd Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sun, 10 Apr 2022 02:35:33 +0300 Subject: [PATCH 13/20] [0.18.0-SNAPSHOT] DynamicProxyHintProcessorTests reinforced and improved --- .../DynamicProxyHintProcessorTests.java | 29 +++++++++++++++++++ .../generated/dynamic-proxy-hint-self.json | 3 ++ .../dynamicproxyhint/source/Self.java | 8 +++++ .../dynamicproxyhint/source/SelfClass.java | 8 +++++ 4 files changed, 48 insertions(+) create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-self.json create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Self.java create mode 100644 graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/SelfClass.java diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java index b4b66a3..42c884a 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintProcessorTests.java @@ -14,6 +14,35 @@ */ class DynamicProxyHintProcessorTests extends ProcessorRunner { + @Test + void selfHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new NativeImageHintProcessor()) + .compile(JavaFileObjects.forResource("dynamicproxyhint/source/Self.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/native-image.properties") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/native-image-config.properties")); + + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("dynamicproxyhint/generated/dynamic-proxy-hint-self.json")); + } + + @Test + void selfClassHintFail() { + final Compilation compilation = Compiler.javac() + .withProcessors(new NativeImageHintProcessor()) + .compile(JavaFileObjects.forResource("dynamicproxyhint/source/SelfClass.java")); + + CompilationSubject.assertThat(compilation).failed(); + } + @Test void configHint() { final Compilation compilation = Compiler.javac() diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-self.json b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-self.json new file mode 100644 index 0000000..e905b12 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/generated/dynamic-proxy-hint-self.json @@ -0,0 +1,3 @@ +[ + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.Self" ] } +] \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Self.java b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Self.java new file mode 100644 index 0000000..9884b25 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/Self.java @@ -0,0 +1,8 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; + +@DynamicProxyHint +public interface Self { + +} diff --git a/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/SelfClass.java b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/SelfClass.java new file mode 100644 index 0000000..d9d3222 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/dynamicproxyhint/source/SelfClass.java @@ -0,0 +1,8 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.DynamicProxyHint; + +@DynamicProxyHint +public class SelfClass { + +} From 877c825e1b12680b943b985ac0f25703fcf16dc5 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sun, 10 Apr 2022 02:52:20 +0300 Subject: [PATCH 14/20] [0.18.0-SNAPSHOT] ResourceHint refactored and contracts changed ResourceHintProcessor supports new refactored annotation --- .../graalvm/hint/annotation/ResourceHint.java | 32 ++++- .../hint/processor/ResourceHintProcessor.java | 125 ++++++++++++++---- 2 files changed, 124 insertions(+), 33 deletions(-) diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/ResourceHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/ResourceHint.java index e423dfa..5f5da44 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/ResourceHint.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/ResourceHint.java @@ -6,7 +6,7 @@ import java.lang.annotation.Target; /** - * Indicate which resources should be pulled into the image. Resources are described by patterns. + * Indicate which resources should be included/excluded when building native-image. * * @see GraalVM Info * @author Anton Kurako (GoodforGod) @@ -17,9 +17,33 @@ public @interface ResourceHint { /** - * Example: @ResourceHint(patterns = { "simplelogger.properties", ".*yaml" }) + * By default, the native-image tool will not integrate any of the resources which are on the + * classpath during the generation into the final image. To make calls such as Class.getResource() + * or Class.getResourceAsStream() (or their corresponding ClassLoader methods) return specific + * resources (instead of null), you must specify the resources that should be accessible at run + * time. + * Example: @ResourceHint(include = { "simplelogger.properties", ".*yaml" }) * - * @return resource patterns specified with Java regexp for regular resources. + * @return resource patterns specified with Java regexp to Include during the generation into the + * final image. */ - String[] patterns(); + String[] include() default {}; + + /** + * Example: @ResourceHint(exclude = { "simplelogger.properties", ".*yaml" }) + * + * @return resource patterns specified with Java regexp to Exclude during the generation into the + * final image. + */ + String[] exclude() default {}; + + /** + * Java localization support (java.util.ResourceBundle) enables Java code to load L10N resources and + * show the right user messages suitable for actual runtime settings like time locale and format, + * etc. + * Example: @ResourceHint(bundles = { "your.pkg.Bundle", "another.pkg.Resource" }) + * + * @return bundle names to include during the generation into the final image. + */ + String[] bundles() default {}; } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java index eb6ad45..4e70a18 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessor.java @@ -4,7 +4,7 @@ import java.lang.annotation.Annotation; import java.util.*; import java.util.stream.Collectors; -import javax.annotation.processing.*; +import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.util.ElementFilter; @@ -20,7 +20,25 @@ public final class ResourceHintProcessor extends AbstractHintProcessor { private static final String FILE_NAME = "resource-config.json"; - private static final String PATTERN = "pattern"; + + private static class Resources { + + private final Set includes = new HashSet<>(); + private final Set excludes = new HashSet<>(); + private final Set bundles = new HashSet<>(); + + boolean haveIncludes() { + return !includes.isEmpty(); + } + + boolean haveExcludes() { + return !excludes.isEmpty(); + } + + boolean haveBundles() { + return !bundles.isEmpty(); + } + } @Override protected Set> getSupportedAnnotations() { @@ -35,49 +53,98 @@ public boolean process(Set annotations, RoundEnvironment try { final Set annotated = roundEnv.getElementsAnnotatedWith(ResourceHint.class); - final Set types = ElementFilter.typesIn(annotated); + final Set elements = ElementFilter.typesIn(annotated); - final Optional resourceConfigJson = getResourceConfigJsonValue(types); - if (resourceConfigJson.isEmpty()) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.MANDATORY_WARNING, - "@ResourceHint found, but patterns are not present"); - return false; - } + final String resourceConfigJson = getResourceConfig(elements); - final HintOrigin origin = getHintOrigin(roundEnv, processingEnv); + final HintOrigin origin = HintUtils.getHintOrigin(roundEnv, processingEnv); final String filePath = origin.getRelativePathForFile(FILE_NAME); - return writeConfigFile(filePath, resourceConfigJson.get(), processingEnv); + return HintUtils.writeConfigFile(filePath, resourceConfigJson, processingEnv); + } catch (HintException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); + return false; } catch (Exception e) { e.printStackTrace(); return false; } } - private static Optional getResourceConfigJsonValue(Set types) { - final Collection resourcePatterns = getGraalVMResourcePattens(types); - if (resourcePatterns.isEmpty()) { - return Optional.empty(); + private static String getResourceConfig(Set elements) { + final Resources resources = getResources(elements); + final StringBuilder configBuilder = new StringBuilder(); + configBuilder.append("{"); + if (resources.haveIncludes() || resources.haveExcludes()) { + configBuilder.append("\n \"resources\": {\n"); + if (resources.haveIncludes()) { + final String includePart = getResourceConfigPart("includes", resources.includes); + configBuilder.append(includePart); + } + + if (resources.haveExcludes()) { + if (resources.haveIncludes()) { + configBuilder.append(",\n"); + } + + final String excludePart = getResourceConfigPart("excludes", resources.excludes); + configBuilder.append(excludePart); + } + + if (resources.haveBundles()) { + configBuilder.append("\n },"); + } else { + configBuilder.append("\n }"); + } } - final String resourceConfig = resourcePatterns.stream() - .map(ResourceHintProcessor::mapPatternToGraalVM) + if (resources.haveBundles()) { + configBuilder.append("\n"); + final String bundlePart = getBundleConfigPart(resources.bundles); + configBuilder.append(bundlePart); + } + + configBuilder.append("\n}"); + + return configBuilder.toString(); + } + + private static String getResourceConfigPart(String partName, Collection resources) { + return resources.stream() .sorted() - .map(resource -> Map.of(PATTERN, resource)) - .flatMap(m -> m.entrySet().stream()) - .map(r -> String.format(" { \"%s\" : \"%s\" }", r.getKey(), r.getValue())) - .collect(Collectors.joining(",\n", "{\n \"resources\": [\n", "\n ]\n}")); + .map(resource -> String.format(" { \"%s\": \"%s\" }", "pattern", resource)) + .collect(Collectors.joining(",\n", " \"" + partName + "\": [\n", "\n ]")); + } - return Optional.of(resourceConfig); + private static String getBundleConfigPart(Collection bundles) { + return bundles.stream() + .sorted() + .map(bundle -> String.format(" { \"%s\": \"%s\" }", "name", bundle)) + .collect(Collectors.joining(",\n", " \"bundles\": [\n", "\n ]")); } - private static Collection getGraalVMResourcePattens(Set types) { - return types.stream() - .flatMap(t -> Arrays.stream(t.getAnnotation(ResourceHint.class).patterns())) - .filter(r -> !r.isBlank()) - .collect(Collectors.toSet()); + private static Resources getResources(Set elements) { + final Resources resources = new Resources(); + for (TypeElement element : elements) { + final ResourceHint annotation = element.getAnnotation(ResourceHint.class); + final List includeBatch = filterValues(annotation.include()); + final List excludeBatch = filterValues(annotation.exclude()); + final List bundleBatch = filterValues(annotation.bundles()); + if (includeBatch.isEmpty() && excludeBatch.isEmpty() && bundleBatch.isEmpty()) { + throw new HintException(element.getQualifiedName().toString() + " is annotated with @" + + ResourceHint.class.getSimpleName() + + ", but no valid 'include' or 'exclude' or 'bundle' parameters specified!"); + } + + resources.includes.addAll(includeBatch); + resources.excludes.addAll(excludeBatch); + resources.bundles.addAll(bundleBatch); + } + + return resources; } - private static String mapPatternToGraalVM(String pattern) { - return pattern; + private static List filterValues(String[] stringValues) { + return Arrays.stream(stringValues) + .filter(a -> !a.isBlank()) + .collect(Collectors.toList()); } } From ba51d48cde7b3ec50ba3e554f9d2281c012b201b Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sun, 10 Apr 2022 02:53:11 +0300 Subject: [PATCH 15/20] [0.18.0-SNAPSHOT] ResourceHintProcessorTests refactored, reinforced, updated and improved --- .../processor/ResourceHintProcessorTests.java | 111 ++++++++++++++++-- .../generated/resource-config-all.json | 14 +++ .../generated/resource-config-bundle.json | 5 + .../resource-config-exclude-and-bundle.json | 10 ++ .../generated/resource-config-exclude.json | 7 ++ .../resource-config-include-and-bundle.json | 11 ++ .../resource-config-include-and-exclude.json | 11 ++ .../generated/resource-config-include.json | 8 ++ .../generated/resource-config-single.json | 6 - .../generated/resource-config.json | 7 -- .../resourcehint/source/ResourceAll.java | 12 ++ ...ResourceNames.java => ResourceBundle.java} | 4 +- ...sourcePatterns.java => ResourceEmpty.java} | 4 +- .../resourcehint/source/ResourceExclude.java | 8 ++ .../resourcehint/source/ResourceInclude.java | 8 ++ 15 files changed, 202 insertions(+), 24 deletions(-) create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-all.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-bundle.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude-and-bundle.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-bundle.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-exclude.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include.json delete mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-single.json delete mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config.json create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceAll.java rename graalvm-hint-processor/src/test/resources/resourcehint/source/{ResourceNames.java => ResourceBundle.java} (51%) rename graalvm-hint-processor/src/test/resources/resourcehint/source/{ResourcePatterns.java => ResourceEmpty.java} (61%) create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceExclude.java create mode 100644 graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceInclude.java diff --git a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java index dff5f76..6a04eb6 100644 --- a/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java +++ b/graalvm-hint-processor/src/test/java/io/goodforgod/graalvm/hint/processor/ResourceHintProcessorTests.java @@ -15,31 +15,128 @@ class ResourceHintProcessorTests extends ProcessorRunner { @Test - void resourceHintForClass() { + void includeHint() { final Compilation compilation = Compiler.javac() .withProcessors(new ResourceHintProcessor()) - .compile(JavaFileObjects.forResource("resourcehint/source/ResourceNames.java")); + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceInclude.java")); CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") .contentsAsString(StandardCharsets.UTF_8) - .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-single.json")); + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-include.json")); } @Test - void resourceHintForMultipleClasses() { + void excludeHint() { final Compilation compilation = Compiler.javac() .withProcessors(new ResourceHintProcessor()) - .compile(JavaFileObjects.forResource("resourcehint/source/ResourceNames.java"), - JavaFileObjects.forResource("resourcehint/source/ResourcePatterns.java")); + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceExclude.java")); CompilationSubject.assertThat(compilation).succeeded(); CompilationSubject.assertThat(compilation) .generatedFile(StandardLocation.CLASS_OUTPUT, "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") .contentsAsString(StandardCharsets.UTF_8) - .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config.json")); + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-exclude.json")); + } + + @Test + void bundleHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceBundle.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-bundle.json")); + } + + @Test + void emptyHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceEmpty.java")); + + CompilationSubject.assertThat(compilation).failed(); + } + + @Test + void includeAndExcludeMultipleFilesHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceInclude.java"), + JavaFileObjects.forResource("resourcehint/source/ResourceExclude.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-include-and-exclude.json")); + } + + @Test + void includeAndBundleMultipleFilesHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceInclude.java"), + JavaFileObjects.forResource("resourcehint/source/ResourceBundle.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-include-and-bundle.json")); + } + + @Test + void excludeAndBundleMultipleFilesHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceExclude.java"), + JavaFileObjects.forResource("resourcehint/source/ResourceBundle.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-exclude-and-bundle.json")); + } + + @Test + void includeAndExcludeAndBundleOneFileHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceAll.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-all.json")); + } + + @Test + void includeAndExcludeAndBundleMultipleFilesHint() { + final Compilation compilation = Compiler.javac() + .withProcessors(new ResourceHintProcessor()) + .compile(JavaFileObjects.forResource("resourcehint/source/ResourceInclude.java"), + JavaFileObjects.forResource("resourcehint/source/ResourceExclude.java"), + JavaFileObjects.forResource("resourcehint/source/ResourceBundle.java")); + + CompilationSubject.assertThat(compilation).succeeded(); + CompilationSubject.assertThat(compilation) + .generatedFile(StandardLocation.CLASS_OUTPUT, + "META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/resource-config.json") + .contentsAsString(StandardCharsets.UTF_8) + .isEqualTo(getResourceContentAsString("resourcehint/generated/resource-config-all.json")); } } diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-all.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-all.json new file mode 100644 index 0000000..a055a99 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-all.json @@ -0,0 +1,14 @@ +{ + "resources": { + "includes": [ + { "pattern": "application.yml" }, + { "pattern": "simplelogger.properties" } + ], + "excludes": [ + { "pattern": "*.xml" } + ] + }, + "bundles": [ + { "name": "your.pkg.Bundle" } + ] +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-bundle.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-bundle.json new file mode 100644 index 0000000..ac5b16f --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-bundle.json @@ -0,0 +1,5 @@ +{ + "bundles": [ + { "name": "your.pkg.Bundle" } + ] +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude-and-bundle.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude-and-bundle.json new file mode 100644 index 0000000..c9d3b6f --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude-and-bundle.json @@ -0,0 +1,10 @@ +{ + "resources": { + "excludes": [ + { "pattern": "*.xml" } + ] + }, + "bundles": [ + { "name": "your.pkg.Bundle" } + ] +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude.json new file mode 100644 index 0000000..7b5dc51 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-exclude.json @@ -0,0 +1,7 @@ +{ + "resources": { + "excludes": [ + { "pattern": "*.xml" } + ] + } +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-bundle.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-bundle.json new file mode 100644 index 0000000..cb9af51 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-bundle.json @@ -0,0 +1,11 @@ +{ + "resources": { + "includes": [ + { "pattern": "application.yml" }, + { "pattern": "simplelogger.properties" } + ] + }, + "bundles": [ + { "name": "your.pkg.Bundle" } + ] +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-exclude.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-exclude.json new file mode 100644 index 0000000..263ed64 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include-and-exclude.json @@ -0,0 +1,11 @@ +{ + "resources": { + "includes": [ + { "pattern": "application.yml" }, + { "pattern": "simplelogger.properties" } + ], + "excludes": [ + { "pattern": "*.xml" } + ] + } +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include.json new file mode 100644 index 0000000..37f1c3f --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-include.json @@ -0,0 +1,8 @@ +{ + "resources": { + "includes": [ + { "pattern": "application.yml" }, + { "pattern": "simplelogger.properties" } + ] + } +} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-single.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-single.json deleted file mode 100644 index 1d7b83b..0000000 --- a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config-single.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "resources": [ - { "pattern" : "application.yml" }, - { "pattern" : "simplelogger.properties" } - ] -} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config.json b/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config.json deleted file mode 100644 index 2f3d009..0000000 --- a/graalvm-hint-processor/src/test/resources/resourcehint/generated/resource-config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "resources": [ - { "pattern" : "*.xml" }, - { "pattern" : "application.yml" }, - { "pattern" : "simplelogger.properties" } - ] -} \ No newline at end of file diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceAll.java b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceAll.java new file mode 100644 index 0000000..e9f4fd5 --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceAll.java @@ -0,0 +1,12 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.ResourceHint; + +@ResourceHint( + include = { "simplelogger.properties", "application.yml" }, + exclude = {"*.xml"}, + bundles = {"your.pkg.Bundle"} +) +public class ResourceAll { + +} diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceNames.java b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceBundle.java similarity index 51% rename from graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceNames.java rename to graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceBundle.java index dc69e9d..7ca8fcd 100644 --- a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceNames.java +++ b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceBundle.java @@ -2,7 +2,7 @@ import io.goodforgod.graalvm.hint.annotation.ResourceHint; -@ResourceHint(patterns = { "simplelogger.properties", "application.yml" }) -public class ResourceNames { +@ResourceHint(bundles = {"your.pkg.Bundle"}) +public class ResourceBundle { } diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourcePatterns.java b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceEmpty.java similarity index 61% rename from graalvm-hint-processor/src/test/resources/resourcehint/source/ResourcePatterns.java rename to graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceEmpty.java index 5969dc1..d2f71c8 100644 --- a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourcePatterns.java +++ b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceEmpty.java @@ -2,7 +2,7 @@ import io.goodforgod.graalvm.hint.annotation.ResourceHint; -@ResourceHint(patterns = {"*.xml"}) -public class ResourcePatterns { +@ResourceHint +public class ResourceEmpty { } diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceExclude.java b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceExclude.java new file mode 100644 index 0000000..5ef481c --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceExclude.java @@ -0,0 +1,8 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.ResourceHint; + +@ResourceHint(exclude = {"*.xml"}) +public class ResourceExclude { + +} diff --git a/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceInclude.java b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceInclude.java new file mode 100644 index 0000000..20be33a --- /dev/null +++ b/graalvm-hint-processor/src/test/resources/resourcehint/source/ResourceInclude.java @@ -0,0 +1,8 @@ +package io.goodforgod.graalvm.hint.processor; + +import io.goodforgod.graalvm.hint.annotation.ResourceHint; + +@ResourceHint(include = { "simplelogger.properties", "application.yml" }) +public class ResourceInclude { + +} From 7642a1907cae898b141b55ebd0519a4b04a89be9 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Sun, 10 Apr 2022 13:50:04 +0300 Subject: [PATCH 16/20] [0.18.0-SNAPSHOT] DynamicProxyHint.Configuration#interfaces mandatory DynamicProxyHint.Configuration target non set OptionParser minor method name refactored --- .../graalvm/hint/annotation/DynamicProxyHint.java | 3 ++- .../hint/processor/DynamicProxyHintParser.java | 6 +----- .../hint/processor/InitializationHintParser.java | 2 +- .../hint/processor/NativeImageHintParser.java | 2 +- .../hint/processor/NativeImageHintProcessor.java | 2 +- .../graalvm/hint/processor/OptionParser.java | 13 +++++++++++-- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java index 8d85880..eeb8e96 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java @@ -19,13 +19,14 @@ @Retention(RetentionPolicy.SOURCE) public @interface DynamicProxyHint { + @Target({}) @Retention(RetentionPolicy.SOURCE) @interface Configuration { /** * @return The interfaces to provide a hint (preferred because typesafe) */ - Class[] interfaces() default {}; + Class[] interfaces(); } /** diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java index fcd35e3..29e08b7 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java @@ -35,7 +35,7 @@ public List getInterfaces() { } @Override - public List> annotations() { + public List> getSupportedAnnotations() { return List.of(DynamicProxyHint.class); } @@ -120,10 +120,6 @@ private List getDynamicProxyConfigurations(TypeElement element) { private boolean isSelfConfiguration(TypeElement element) { final DynamicProxyHint annotation = element.getAnnotation(DynamicProxyHint.class); - if (annotation == null) { - return false; - } - return (annotation.resources() == null || annotation.resources().length == 0) && (annotation.files() == null || annotation.files().length == 0); } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java index 0a01142..fc6daa4 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/InitializationHintParser.java @@ -55,7 +55,7 @@ public int hashCode() { } @Override - public List> annotations() { + public List> getSupportedAnnotations() { return List.of(InitializationHint.class, InitializationHints.class); } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java index 8987c80..77f28fb 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintParser.java @@ -45,7 +45,7 @@ public String toString() { } @Override - public List> annotations() { + public List> getSupportedAnnotations() { return List.of(NativeImageHint.class); } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java index 8d99417..8cf7050 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/NativeImageHintProcessor.java @@ -59,7 +59,7 @@ public boolean process(Set annotatedElements, RoundEnviro if (options.isEmpty()) { final String annotations = OPTION_PARSERS.stream() - .flatMap(p -> p.annotations().stream() + .flatMap(p -> p.getSupportedAnnotations().stream() .filter(a -> !roundEnv.getElementsAnnotatedWith(a).isEmpty())) .map(Class::getSimpleName) .collect(Collectors.joining(",")); diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java index a75d277..4169b98 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/OptionParser.java @@ -1,19 +1,28 @@ package io.goodforgod.graalvm.hint.processor; +import io.goodforgod.graalvm.hint.annotation.NativeImageHint; import java.lang.annotation.Annotation; import java.util.List; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; /** - * Contract for hint parser that produces options + * Hint parser that produces options for {@link NativeImageHint#optionNames()} * * @author Anton Kurako (GoodforGod) * @since 07.04.2022 */ interface OptionParser { - List> annotations(); + /** + * @return annotation parser supports + */ + List> getSupportedAnnotations(); + /** + * @param roundEnv parser invoked in + * @param processingEnv parser invoked in + * @return list of {@link NativeImageHint#optionNames()} to include + */ List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv); } From 521b7040564f6a8efe64bea5779048452b2ee63e Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Mon, 11 Apr 2022 00:46:41 +0300 Subject: [PATCH 17/20] [0.18.0-SNAPSHOT] README.md ResourceHint examples updated build.gradle description updated --- README.md | 55 +++++++++++++++++++++++---- graalvm-hint-annotations/build.gradle | 2 +- graalvm-hint-processor/build.gradle | 2 +- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ab6aeb5..ec59d23 100644 --- a/README.md +++ b/README.md @@ -138,11 +138,12 @@ Resulted reflection-config.json: You can read more about GraalVM resource configuration [here](https://www.graalvm.org/reference-manual/native-image/Resources/). -Hint allows generating config for resource files to include into native application. +Hint allows generating config for resource files to be included/excluded when building native application. +You can also include bundles into native image using this Hint. -Hint configuration: +Include Hint: ```java -@ResourceHint(patterns = { "simplelogger.properties", "application.yml", "*.xml" }) +@ResourceHint(include = { "simplelogger.properties", "application.yml", "*.xml" }) public class ResourceNames { } @@ -151,10 +152,48 @@ public class ResourceNames { Resulted resource-config.json: ```json { - "resources": [ - { "pattern" : "*.xml" }, - { "pattern" : "application.yml" }, - { "pattern" : "simplelogger.properties" } + "resources": { + "includes": [ + { "pattern" : "*.xml" }, + { "pattern": "application.yml" }, + { "pattern": "simplelogger.properties" } + ] + } +} +``` + +Exclude Hint: +```java +@ResourceHint(exclude = { "*.xml" }) +public class ResourceNames { + +} +``` + +Resulted resource-config.json: +```json +{ + "resources": { + "excludes": [ + { "pattern": "*.xml" } + ] + } +} +``` + +Bundle Hint: +```java +@ResourceHint(bundles = { "your.pkg.Bundle" }) +public class ResourceNames { + +} +``` + +Resulted resource-config.json: +```json +{ + "bundles": [ + { "name": "your.pkg.Bundle" } ] } ``` @@ -190,7 +229,7 @@ public class Entrypoint { Resulted native-image.properties: ```properties -Args = -H:Name=myapp -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint \ +Args = -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint -H:Name=myapp \ -H:+PrintClassInitialization \ -H:+InlineBeforeAnalysis ``` diff --git a/graalvm-hint-annotations/build.gradle b/graalvm-hint-annotations/build.gradle index 922fea5..02403b9 100644 --- a/graalvm-hint-annotations/build.gradle +++ b/graalvm-hint-annotations/build.gradle @@ -6,7 +6,7 @@ publishing { pom { name = "GraalVM Hint Annotations" url = "https://github.com/GoodforGod/$artifactRootId" - description = "GraalVM Hint Annotations helps marking GraalVM hints for GraalVM Hint Processor." + description = "Annotations that help marking GraalVM native-image hints for GraalVM Hint Processor." license { name = "Apache License 2.0" diff --git a/graalvm-hint-processor/build.gradle b/graalvm-hint-processor/build.gradle index df4f167..cb5dde3 100644 --- a/graalvm-hint-processor/build.gradle +++ b/graalvm-hint-processor/build.gradle @@ -28,7 +28,7 @@ publishing { pom { name = "GraalVM Hint Processor" url = "https://github.com/GoodforGod/$artifactRootId" - description = "GraalVM Hint Processor that generates GraalVM configuration hints for native-image applications." + description = "Annotation Processors that generate GraalVM configuration hints for native-image applications." license { name = "Apache License 2.0" From c59c23ae1b7962747bd8e773932a74343bcd65ac Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 13 Apr 2022 20:52:13 +0300 Subject: [PATCH 18/20] [0.18.0-SNAPSHOT] HintUtils#getPackage improvements --- .../hint/processor/DynamicProxyHintParser.java | 5 +++-- .../graalvm/hint/processor/HintUtils.java | 17 +++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java index 29e08b7..fa23e0f 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/DynamicProxyHintParser.java @@ -91,6 +91,7 @@ public List getOptions(RoundEnvironment roundEnv, ProcessingEnvironment private List getDynamicProxyConfigurations(TypeElement element) { final String annotationName = DynamicProxyHint.Configuration.class.getSimpleName(); final String annotationParent = DynamicProxyHint.class.getSimpleName(); + final String elementName = element.getQualifiedName().toString(); final AnnotationTypeFieldVisitor visitor = new AnnotationTypeFieldVisitor(annotationName, "interfaces"); final List interfaceConfigurations = element.getAnnotationMirrors().stream() .filter(a -> a.getAnnotationType().asElement().getSimpleName().contentEquals(annotationParent)) @@ -108,9 +109,9 @@ private List getDynamicProxyConfigurations(TypeElement element) { if (interfaceConfigurations.isEmpty() && isSelfConfiguration(element)) { if (element.getKind().isInterface()) { - interfaceConfigurations.add(new Configuration(List.of(element.getQualifiedName().toString()))); + interfaceConfigurations.add(new Configuration(List.of(elementName))); } else { - throw new HintException(element.getQualifiedName().toString() + " is annotated with @" + throw new HintException(elementName + " is annotated with @" + DynamicProxyHint.class.getSimpleName() + " hint but is not an interface"); } } diff --git a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java index 0054880..bfb3c62 100644 --- a/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java +++ b/graalvm-hint-processor/src/main/java/io/goodforgod/graalvm/hint/processor/HintUtils.java @@ -29,7 +29,7 @@ static HintOrigin getHintOrigin(RoundEnvironment roundEnv, ProcessingEnvironment final String group = (options.containsKey(HintOrigin.HINT_PROCESSING_GROUP)) ? options.get(HintOrigin.HINT_PROCESSING_GROUP) - : getPackage(anyElement); + : getPackage(processingEnv, anyElement); final String artifact = (options.containsKey(HintOrigin.HINT_PROCESSING_ARTIFACT)) ? options.get(HintOrigin.HINT_PROCESSING_ARTIFACT) @@ -123,13 +123,18 @@ static boolean writeConfigFile(String filePath, String data, ProcessingEnvironme return true; } - private static String getPackage(Element element) { - final Element enclosingElement = element.getEnclosingElement(); - if (enclosingElement instanceof PackageElement) { - return ((PackageElement) enclosingElement).getQualifiedName().toString(); + private static String getPackage(ProcessingEnvironment processingEnv, Element element) { + final PackageElement packageElement = processingEnv.getElementUtils().getPackageOf(element); + if (packageElement == null || packageElement.isUnnamed()) { + return HintOrigin.DEFAULT_PACKAGE; } - return HintOrigin.DEFAULT_PACKAGE; + final String packageName = packageElement.getQualifiedName().toString(); + if (packageName.isEmpty()) { + return HintOrigin.DEFAULT_PACKAGE; + } + + return packageName; } private static String getArtifact(Element element) { From 3087af89611fdbc24056ca80e42f7b16378eefbc Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Thu, 14 Apr 2022 00:57:36 +0300 Subject: [PATCH 19/20] [0.18.0-SNAPSHOT] README.md updated DynamicProxyHint javadoc updated --- README.md | 100 ++++++++++++------ .../hint/annotation/DynamicProxyHint.java | 4 +- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index ec59d23..7e77800 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Features: - Generate Resource Hints ([resource-config.json](#resourcehint)) - Generate Options hints ([native-image.properties](#nativeimagehint)) - Generate Initialization Hints ([native-image.properties](#initializationhint)) +- Generate Dynamic Proxy Hints ([dynamic-proxy-hint.json](#dynamicproxyhint)) - Generate JNI Hints ([jni-config.json](#jnihint)) ## Dependency :rocket: @@ -23,8 +24,8 @@ Java 11+ is supported. [**Gradle**](https://mvnrepository.com/artifact/io.goodforgod/graalvm-hint-processor) ```groovy -annotationProcessor "io.goodforgod:graalvm-hint-processor:0.17.1" -compilyOnly "io.goodforgod:graalvm-hint-annotations:0.17.1" +annotationProcessor "io.goodforgod:graalvm-hint-processor:0.18.0" +compilyOnly "io.goodforgod:graalvm-hint-annotations:0.18.0" ``` [**Maven**](https://mvnrepository.com/artifact/io.goodforgod/graalvm-hint-processor) @@ -33,14 +34,14 @@ compilyOnly "io.goodforgod:graalvm-hint-annotations:0.17.1" io.goodforgod graalvm-hint-annotations - 0.17.1 + 0.18.0 compile true io.goodforgod graalvm-hint-processor - 0.17.1 + 0.18.0 provided @@ -58,7 +59,7 @@ compilyOnly "io.goodforgod:graalvm-hint-annotations:0.17.1" io.goodforgod graalvm-hint-processor - 0.17.1 + 0.18.0 @@ -67,13 +68,9 @@ compilyOnly "io.goodforgod:graalvm-hint-annotations:0.17.1" ``` -## Examples +## ReflectionHint -Below are illustrated examples for usage of such library. - -### ReflectionHint - -You can read more about GraalVM reflection configuration [here](https://www.graalvm.org/reference-manual/native-image/Reflection/). +You can read more about GraalVM reflection configuration [in official documentation here](https://www.graalvm.org/reference-manual/native-image/Reflection/). There are available access hints: - allPublicFields @@ -94,7 +91,7 @@ public class RequestOnly { } ``` -Generated reflection config: +Generated *reflection-config.json*: ```json [{ "name": "io.goodforgod.graalvm.hint.processor.RequestOnly", @@ -116,7 +113,7 @@ public class ReflectionConfig { } ``` -Resulted reflection-config.json: +Generated *reflection-config.json*: ```json [{ "name": "io.goodforgod.graalvm.hint.processor", @@ -134,9 +131,9 @@ Resulted reflection-config.json: }] ``` -### ResourceHint +## ResourceHint -You can read more about GraalVM resource configuration [here](https://www.graalvm.org/reference-manual/native-image/Resources/). +You can read more about GraalVM resource configuration [in official documentation here](https://www.graalvm.org/reference-manual/native-image/Resources/). Hint allows generating config for resource files to be included/excluded when building native application. You can also include bundles into native image using this Hint. @@ -149,7 +146,7 @@ public class ResourceNames { } ``` -Resulted resource-config.json: +Generated *resource-config.json*: ```json { "resources": { @@ -170,7 +167,7 @@ public class ResourceNames { } ``` -Resulted resource-config.json: +Generated *resource-config.json*: ```json { "resources": { @@ -189,7 +186,7 @@ public class ResourceNames { } ``` -Resulted resource-config.json: +Generated *resource-config.json*: ```json { "bundles": [ @@ -198,9 +195,9 @@ Resulted resource-config.json: } ``` -### NativeImageHint +## NativeImageHint -You can read more about GraalVM native-image options [here](https://www.graalvm.org/reference-manual/native-image/Options/). +You can read more about GraalVM native-image options [in official documentation here](https://www.graalvm.org/reference-manual/native-image/Options/). Hint allows generating config for native-image options and initial application entrypoint. @@ -213,7 +210,7 @@ public class EntrypointOnly { } ``` -Resulted native-image.properties: +Generated *native-image.properties*: ```properties Args = -H:Class=io.goodforgod.graalvm.hint.processor.EntrypointOnly ``` @@ -227,16 +224,16 @@ public class Entrypoint { } ``` -Resulted native-image.properties: +Generated *native-image.properties*: ```properties Args = -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint -H:Name=myapp \ -H:+PrintClassInitialization \ -H:+InlineBeforeAnalysis ``` -### InitializationHint +## InitializationHint -You can read more about GraalVM initialization configuration [here](https://www.graalvm.org/reference-manual/native-image/ClassInitialization/). +You can read more about GraalVM initialization configuration [in official documentation here](https://www.graalvm.org/reference-manual/native-image/ClassInitialization/). Hint allows generating config for what classes to instantiate in runtime and what classes to instantiate in compile time. @@ -249,7 +246,7 @@ public class EntrypointOnly { } ``` -Resulted native-image.properties: +Generated *native-image.properties*: ```properties Args = --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor @@ -266,16 +263,59 @@ public class Entrypoint { } ``` -Resulted native-image.properties: +Generated *native-image.properties*: ```properties Args = -H:Class=io.goodforgod.graalvm.hint.processor.Entrypoint \ --initialize-at-build-time=io.goodforgod.graalvm.hint.processor.HintOrigin.class \ --initialize-at-run-time=io.goodforgod.graalvm.hint.processor ``` -### JniHint +## DynamicProxyHint + +You can read more about GraalVM DynamicProxyHint configuration [in official documentation here](https://www.graalvm.org/reference-manual/native-image/DynamicProxy/). + +Use can pass dynamic proxy resources (*-H:DynamicProxyConfigurationResources*) or files (*-H:DynamicProxyConfigurationFiles*) using corresponding options: +```java +@DynamicProxyHint(resources = {"proxy-resource.json"}, files = {"proxy-file.json"}) +public class Resource { + +} +``` + +Generated *native-image.properties*: +```properties +Args = -H:DynamicProxyConfigurationFiles=proxy-file.json \ + -H:DynamicProxyConfigurationResources=proxy-resource.json +``` + +You can configure files yourself using annotations only without the need for manually creating JSON configurations. + +```java +@DynamicProxyHint(value = { + @DynamicProxyHint.Configuration(interfaces = {OptionParser.class, HintOrigin.class}), + @DynamicProxyHint.Configuration(interfaces = {HintOrigin.class}) +}) +public class Config { + +} +``` + +Generated *dynamic-proxy-hint-config.json*: +```json +[ + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.OptionParser", "io.goodforgod.graalvm.hint.processor.HintOrigin" ] }, + { "interfaces": [ "io.goodforgod.graalvm.hint.processor.HintOrigin" ] } +] +``` + +Generated *native-image.properties*: +```properties +Args = -H:DynamicProxyConfigurationResources=META-INF/native-image/io.goodforgod.graalvm.hint.processor/hint/dynamic-proxy-config.json +``` + +## JniHint -You can read more about GraalVM JNI configuration [here](https://www.graalvm.org/reference-manual/native-image/JNI/). +You can read more about GraalVM JNI configuration [in official documentation here](https://www.graalvm.org/reference-manual/native-image/JNI/). There are available JNI access hints: - allPublicFields @@ -294,7 +334,7 @@ public class RequestOnly { } ``` -Generated JNI config: +Generated *jni-config.json*: ```json [{ "name": "io.goodforgod.graalvm.hint.processor.RequestOnly", @@ -315,7 +355,7 @@ public final class JniConfig { } ``` -Resulted jni-config.json: +Generated *jni-config.json*: ```json [{ "name": "io.goodforgod.graalvm.hint.processor", diff --git a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java index eeb8e96..a0f910f 100644 --- a/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java +++ b/graalvm-hint-annotations/src/main/java/io/goodforgod/graalvm/hint/annotation/DynamicProxyHint.java @@ -37,12 +37,12 @@ Configuration[] value() default {}; /** - * @return file configs to include under DynamicProxyConfigurationFiles option + * @return file configs to include under -H:DynamicProxyConfigurationFiles option */ String[] files() default {}; /** - * @return resources configs to include under DynamicProxyConfigurationResources option + * @return resources configs to include under -H:DynamicProxyConfigurationResources option */ String[] resources() default {}; } From 2d6d2d91e21feedaca34f15b5e7fa3481bd87b10 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Thu, 14 Apr 2022 00:58:02 +0300 Subject: [PATCH 20/20] [0.18.0] Release ready --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index d3a7492..8419a04 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ groupId=io.goodforgod artifactRootId=graalvm-hint -artifactVersion=0.18.0-SNAPSHOT +artifactVersion=0.18.0 ##### GRADLE #####