Skip to content

Commit c212bc9

Browse files
authored
Adds synthetic constructs. General cleanup. (#37)
Signed-off-by: Laird Nelson <ljnelson@gmail.com>
1 parent dc3feb4 commit c212bc9

7 files changed

Lines changed: 389 additions & 12 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ dependency:
3636
Always check https://search.maven.org/artifact/org.microbean/microbean-construct
3737
for up-to-date available versions.
3838
-->
39-
<version>0.0.21</version>
39+
<version>0.0.22</version>
4040
</dependency>
4141
```
4242

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@
274274
</plugin>
275275
<plugin>
276276
<artifactId>maven-compiler-plugin</artifactId>
277-
<version>3.14.1</version>
277+
<version>3.15.0</version>
278278
<configuration>
279279
<compilerArgs>
280280
<arg>-Xlint:all</arg>
@@ -369,7 +369,7 @@
369369
<plugin>
370370
<groupId>org.codehaus.mojo</groupId>
371371
<artifactId>versions-maven-plugin</artifactId>
372-
<version>2.20.1</version>
372+
<version>2.21.0</version>
373373
</plugin>
374374
<plugin>
375375
<groupId>io.smallrye</groupId>

src/main/java/org/microbean/construct/element/SyntheticAnnotationMirror.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
import java.lang.constant.ConstantDesc;
1919
import java.lang.constant.DynamicConstantDesc;
2020

21+
import java.util.Iterator;
2122
import java.util.LinkedHashMap;
2223
import java.util.List;
2324
import java.util.Map;
25+
import java.util.Map.Entry;
2426
import java.util.Optional;
2527

2628
import javax.lang.model.element.AnnotationMirror;
@@ -69,7 +71,7 @@ public final class SyntheticAnnotationMirror implements AnnotationMirror, Consta
6971

7072
private final TypeElement annotationTypeElement;
7173

72-
private final Map<ExecutableElement, AnnotationValue> elementValues;
74+
private final Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues;
7375

7476

7577
/*
@@ -142,6 +144,39 @@ public SyntheticAnnotationMirror(final TypeElement annotationTypeElement,
142144
this.elementValues = m.isEmpty() ? Map.of() : unmodifiableMap(m);
143145
}
144146

147+
/**
148+
* Creates a new {@link SyntheticAnnotationMirror} that is an effective <dfn>copy</dfn> of the supplied {@link
149+
* AnnotationMirror}.
150+
*
151+
* @param a a non-{@code null} {@link AnnotationMirror} to semantically copy
152+
*
153+
* @exception NullPointerException if {@code a} is {@code null}
154+
*/
155+
public SyntheticAnnotationMirror(final AnnotationMirror a) {
156+
super();
157+
this.annotationTypeElement = new SyntheticAnnotationTypeElement((TypeElement)a.getAnnotationType().asElement());
158+
final Map<? extends ExecutableElement, ? extends AnnotationValue> originalElementValues = a.getElementValues();
159+
if (originalElementValues.isEmpty()) {
160+
// If there are no explicit values, then...there are no explicit values whether the annotation interface type
161+
// contains/encloses any elements at all.
162+
this.elementValues = Map.of();
163+
} else {
164+
// There are explicit values. That also means that the annotation interface type contains/encloses at least one
165+
// element.
166+
final List<ExecutableElement> syntheticElements = methodsIn(this.annotationTypeElement.getEnclosedElements());
167+
assert !syntheticElements.isEmpty();
168+
final Map<ExecutableElement, AnnotationValue> newElementValues = newLinkedHashMap(originalElementValues.size());
169+
for (final Entry<? extends ExecutableElement, ? extends AnnotationValue> originalEntry : originalElementValues.entrySet()) {
170+
final ExecutableElement originalElement = originalEntry.getKey();
171+
final ExecutableElement syntheticElement = element(syntheticElements, originalElement.getSimpleName());
172+
if (syntheticElement != null) {
173+
newElementValues.put(syntheticElement, originalEntry.getValue());
174+
}
175+
}
176+
this.elementValues = unmodifiableMap(newElementValues);
177+
}
178+
}
179+
145180

146181
/*
147182
* Instance methods.
@@ -172,6 +207,11 @@ public final DeclaredType getAnnotationType() {
172207
return this.elementValues;
173208
}
174209

210+
@Override
211+
public final String toString() {
212+
return "@" + this.annotationTypeElement.toString(); // TODO: not anywhere near good enough
213+
}
214+
175215

176216
/*
177217
* Static methods.
@@ -197,4 +237,13 @@ private static final Optional<? extends ConstantDesc> describeExecutableElement(
197237
};
198238
}
199239

240+
private static final <E extends Element> E element(final Iterable<? extends E> elements, final CharSequence simpleName) {
241+
for (final E e : elements) {
242+
if (e.getSimpleName().contentEquals(simpleName)) {
243+
return e;
244+
}
245+
}
246+
return null;
247+
}
248+
200249
}

src/main/java/org/microbean/construct/element/SyntheticAnnotationTypeElement.java

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
import static javax.lang.model.type.TypeKind.ARRAY;
5959
import static javax.lang.model.type.TypeKind.DECLARED;
6060

61+
import static javax.lang.model.util.ElementFilter.methodsIn;
62+
6163
import static org.microbean.construct.element.AnnotationMirrors.validAnnotationInterfaceElementScalarType;
6264

6365
/**
@@ -285,6 +287,46 @@ public SyntheticAnnotationTypeElement(final List<? extends AnnotationMirror> ann
285287
this(annotationMirrors, new SyntheticName(fullyQualifiedName), elements);
286288
}
287289

290+
/**
291+
* Creates a new {@link SyntheticAnnotationTypeElement}, mostly, if not exclusively, for use by {@link
292+
* SyntheticAnnotationMirror} instances.
293+
*
294+
* @param e a non-{@code null} {@link TypeElement} whose {@link TypeElement#getKind() getKind()} method returns {@link
295+
* javax.lang.model.element.ElementKind#ANNOTATION_TYPE}
296+
*
297+
* @exception NullPointerException if {@code e} is {@code null}
298+
*
299+
* @exception IllegalArgumentException if the supplied {@link TypeElement}'s {@link TypeElement#getKind() getKind()}
300+
* method does not return {@link javax.lang.model.element.ElementKind#ANNOTATION_TYPE}
301+
*/
302+
public SyntheticAnnotationTypeElement(final TypeElement e) {
303+
super();
304+
if (e.getKind() != ANNOTATION_TYPE) {
305+
throw new IllegalArgumentException("e: " + e);
306+
}
307+
this.annotationMirrors = new CopyOnWriteArrayList<>(e.getAnnotationMirrors());
308+
Name n = e.getSimpleName();
309+
this.sn = n instanceof SyntheticName sn ? sn : new SyntheticName(n.toString());
310+
n = e.getQualifiedName();
311+
this.fqn = n instanceof SyntheticName sn ? sn : new SyntheticName(n.toString());
312+
// Deliberate: Type is an inner class and hence cannot be shared
313+
this.type = new Type();
314+
final List<ExecutableElement> elements = methodsIn(e.getEnclosedElements());
315+
if (elements.isEmpty()) {
316+
this.elements = List.of();
317+
} else {
318+
final List<InternalAnnotationElement> elements0 = new ArrayList<>(elements.size());
319+
for (final ExecutableElement ee :elements) {
320+
// Deliberate: no instanceof InternalAnnotationElement check, i.e. wrapping/copying is deliberate and necessary
321+
elements0.add(new InternalAnnotationElement(ee.getAnnotationMirrors(),
322+
ee.getReturnType(),
323+
ee.getSimpleName(),
324+
ee.getDefaultValue()));
325+
}
326+
this.elements = unmodifiableList(elements0);
327+
}
328+
}
329+
288330
/**
289331
* Creates a new {@link SyntheticAnnotationTypeElement}, mostly, if not exclusively, for use by {@link
290332
* SyntheticAnnotationMirror} instances.
@@ -320,8 +362,8 @@ public SyntheticAnnotationTypeElement(final List<? extends AnnotationMirror> ann
320362
this.elements = List.of();
321363
} else {
322364
final List<InternalAnnotationElement> elements0 = new ArrayList<>(elements.size());
323-
for (final SyntheticAnnotationElement e : elements) {
324-
elements0.add(new InternalAnnotationElement(e.annotationMirrors(), e.type(), e.name(), e.defaultValue()));
365+
for (final SyntheticAnnotationElement sae : elements) {
366+
elements0.add(new InternalAnnotationElement(sae.annotationMirrors(), sae.type(), sae.name(), sae.defaultValue()));
325367
}
326368
this.elements = unmodifiableList(elements0);
327369
}
@@ -572,7 +614,7 @@ public SyntheticAnnotationElement(final List<? extends AnnotationMirror> annotat
572614
case ArrayType t when t.getKind() == ARRAY -> validateScalarType(t.getComponentType());
573615
default -> validateScalarType(type);
574616
};
575-
if (name.equals("getClass") || name.equals("hashCode") || name.equals("toString")) {
617+
if (name.contentEquals("getClass") || name.contentEquals("hashCode") || name.contentEquals("toString")) {
576618
// java.lang.Object-declared methods that might otherwise meet annotation element requirements
577619
throw new IllegalArgumentException("name: " + name);
578620
}
@@ -728,13 +770,15 @@ private final class InternalAnnotationElement implements ExecutableElement {
728770

729771
private InternalAnnotationElement(final List<? extends AnnotationMirror> annotationMirrors,
730772
final TypeMirror type,
731-
final SyntheticName name,
732-
final SyntheticAnnotationValue defaultValue) {
773+
final Name name,
774+
final AnnotationValue defaultValue) {
733775
super();
734776
this.annotationMirrors = new CopyOnWriteArrayList<>(annotationMirrors);
735-
this.t = new Type(type);
736-
this.name = requireNonNull(name, "name");
737-
this.defaultValue = defaultValue;
777+
// This Type is NOT an inner class and cannot receive annotations so this is OK.
778+
this.t = type instanceof Type t ? t : new Type(type);
779+
this.name = name instanceof SyntheticName sn ? sn : new SyntheticName(name);
780+
this.defaultValue =
781+
defaultValue instanceof SyntheticAnnotationValue sav ? sav : new SyntheticAnnotationValue(defaultValue.getValue());
738782
}
739783

740784

@@ -861,6 +905,7 @@ private Type(final TypeMirror type) { // the "return type"
861905
this.type = switch (type) {
862906
case null -> throw new NullPointerException("type");
863907
case ArrayType t when t.getKind() == ARRAY -> validateScalarType(t.getComponentType());
908+
case Type t -> t.type;
864909
default -> validateScalarType(type);
865910
};
866911
}

0 commit comments

Comments
 (0)