|
1 | 1 | /* |
2 | | - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
25 | 25 | package com.oracle.svm.processor; |
26 | 26 |
|
27 | 27 | import java.io.PrintWriter; |
| 28 | +import java.util.ArrayList; |
28 | 29 | import java.util.HashSet; |
29 | 30 | import java.util.List; |
30 | 31 | import java.util.Set; |
|
35 | 36 | import javax.lang.model.element.AnnotationMirror; |
36 | 37 | import javax.lang.model.element.Element; |
37 | 38 | import javax.lang.model.element.TypeElement; |
| 39 | +import javax.lang.model.type.DeclaredType; |
| 40 | +import javax.lang.model.type.TypeKind; |
38 | 41 | import javax.lang.model.type.TypeMirror; |
39 | 42 |
|
40 | 43 | import jdk.graal.compiler.processor.AbstractProcessor; |
@@ -83,21 +86,32 @@ private void processElement(TypeElement annotatedType) { |
83 | 86 | out.println("@Platforms({" + platforms + "})"); |
84 | 87 | } |
85 | 88 | out.println("@" + getSimpleName(AutomaticallyRegisteredFeatureProcessor.ANNOTATION_CLASS_NAME)); |
86 | | - out.println("public final class " + featureClassName + " implements " + |
87 | | - String.join(", ", new String[]{AutomaticallyRegisteredFeatureProcessor.FEATURE_INTERFACE_CLASS_NAME, FEATURE_SINGLETON_NAME, UNSAVED_SINGLETON_NAME}) + " {"); |
| 89 | + List<TypeElement> singletonSuperclasses = getSingletonSuperclasses(annotatedType); |
| 90 | + String supertypes = singletonSuperclasses.isEmpty() |
| 91 | + ? " implements " + String.join(", ", new String[]{AutomaticallyRegisteredFeatureProcessor.FEATURE_INTERFACE_CLASS_NAME, FEATURE_SINGLETON_NAME, UNSAVED_SINGLETON_NAME}) |
| 92 | + : " extends " + getPackage(singletonSuperclasses.get(0)).getQualifiedName().toString() + "." + getTypeNameWithEnclosingClasses(singletonSuperclasses.get(0), "Feature"); |
| 93 | + out.println("public class " + featureClassName + supertypes + " {"); |
88 | 94 | out.println(" @Override"); |
89 | 95 | out.println(" public void afterRegistration(AfterRegistrationAccess access) {"); |
90 | 96 |
|
91 | 97 | List<TypeMirror> onlyWithList = getAnnotationValueList(singletonAnnotation, "onlyWith", TypeMirror.class); |
92 | 98 | if (!onlyWithList.isEmpty()) { |
93 | 99 | for (var onlyWith : onlyWithList) { |
94 | 100 | out.println(" if (!new " + onlyWith + "().getAsBoolean()) {"); |
| 101 | + if (!singletonSuperclasses.isEmpty()) { |
| 102 | + out.println(" super.afterRegistration(access);"); |
| 103 | + } |
95 | 104 | out.println(" return;"); |
96 | 105 | out.println(" }"); |
97 | 106 | } |
98 | 107 | } |
99 | 108 |
|
100 | 109 | List<TypeMirror> keysFromAnnotation = getAnnotationValueList(singletonAnnotation, "value", TypeMirror.class); |
| 110 | + for (var superclass : singletonSuperclasses) { |
| 111 | + AnnotationMirror superclassAnnotation = getAnnotation(superclass, getType(ANNOTATION_CLASS_NAME)); |
| 112 | + keysFromAnnotation.addAll(getAnnotationValueList(superclassAnnotation, "value", TypeMirror.class)); |
| 113 | + } |
| 114 | + |
101 | 115 | if (keysFromAnnotation.isEmpty()) { |
102 | 116 | String keyname = "" + annotatedType + ".class"; |
103 | 117 | out.println(" if (ImageSingletons.lookup(" + LAYERED_SINGLETON_INFO + ".class).handledDuringLoading(" + keyname + ")){"); |
@@ -130,6 +144,29 @@ private void processElement(TypeElement annotatedType) { |
130 | 144 | } |
131 | 145 | } |
132 | 146 |
|
| 147 | + /** |
| 148 | + * Get the inheritance chain from {@code annotatedType} up to (excluding) the first |
| 149 | + * non-{@code @AutomaticallyRegisteredImageSingleton} type. |
| 150 | + * |
| 151 | + * @return a list ordered from the most specific to the least specific, empty if not even the |
| 152 | + * direct superclass is annotated |
| 153 | + */ |
| 154 | + private List<TypeElement> getSingletonSuperclasses(TypeElement annotatedType) { |
| 155 | + List<TypeElement> list = new ArrayList<>(); |
| 156 | + for (TypeElement curr = annotatedType;;) { |
| 157 | + TypeMirror next = curr.getSuperclass(); |
| 158 | + if (next.getKind() != TypeKind.DECLARED) { |
| 159 | + break; |
| 160 | + } |
| 161 | + curr = (TypeElement) ((DeclaredType) next).asElement(); |
| 162 | + if (getAnnotation(curr, getType(ANNOTATION_CLASS_NAME)) == null) { |
| 163 | + break; |
| 164 | + } |
| 165 | + list.add(curr); |
| 166 | + } |
| 167 | + return list; |
| 168 | + } |
| 169 | + |
133 | 170 | /** |
134 | 171 | * We allow inner classes to be annotated. To make the generated service name unique, we need to |
135 | 172 | * concatenate the simple names of all outer classes. |
|
0 commit comments