7193719: Support repeating annotations in javax.lang.model
Reviewed-by: jjg
This commit is contained in:
parent
7518dede81
commit
9e3a121357
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -450,7 +450,7 @@ public abstract class Symbol implements Element {
|
||||
* This is the implementation for {@code
|
||||
* javax.lang.model.element.Element.getAnnotationMirrors()}.
|
||||
*/
|
||||
public final List<Attribute.Compound> getAnnotationMirrors() {
|
||||
public final List<? extends AnnotationMirror> getAnnotationMirrors() {
|
||||
return getRawAttributes();
|
||||
}
|
||||
|
||||
@ -462,6 +462,11 @@ public abstract class Symbol implements Element {
|
||||
return JavacElements.getAnnotation(this, annoType);
|
||||
}
|
||||
|
||||
// This method is part of the javax.lang.model API, do not use this in javac code.
|
||||
public <A extends java.lang.annotation.Annotation> A[] getAnnotations(Class<A> annoType) {
|
||||
return JavacElements.getAnnotations(this, annoType);
|
||||
}
|
||||
|
||||
// TODO: getEnclosedElements should return a javac List, fix in FilteredMemberList
|
||||
public java.util.List<Symbol> getEnclosedElements() {
|
||||
return List.nil();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,6 +27,8 @@ package com.sun.tools.javac.model;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.lang.model.SourceVersion;
|
||||
@ -96,32 +98,43 @@ public class JavacElements implements Elements {
|
||||
enter = Enter.instance(context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An internal-use utility that creates a reified annotation.
|
||||
* An internal-use utility that creates a runtime view of an
|
||||
* annotation. This is the implementation of
|
||||
* Element.getAnnotation(Class).
|
||||
*/
|
||||
public static <A extends Annotation> A getAnnotation(Symbol annotated,
|
||||
Class<A> annoType) {
|
||||
if (!annoType.isAnnotation())
|
||||
throw new IllegalArgumentException("Not an annotation type: "
|
||||
+ annoType);
|
||||
String name = annoType.getName();
|
||||
for (Attribute.Compound anno : annotated.getAnnotationMirrors())
|
||||
if (name.equals(anno.type.tsym.flatName().toString()))
|
||||
return AnnotationProxyMaker.generateAnnotation(anno, annoType);
|
||||
return null;
|
||||
Attribute.Compound c;
|
||||
if (annotated.kind == Kinds.TYP && annotated instanceof ClassSymbol) {
|
||||
c = getAttributeOnClass((ClassSymbol)annotated, annoType);
|
||||
} else {
|
||||
c = getAttribute(annotated, annoType);
|
||||
}
|
||||
return c == null ? null : AnnotationProxyMaker.generateAnnotation(c, annoType);
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal-use utility that creates a reified annotation.
|
||||
* This overloaded version take annotation inheritance into account.
|
||||
*/
|
||||
public static <A extends Annotation> A getAnnotation(ClassSymbol annotated,
|
||||
Class<A> annoType) {
|
||||
// Helper to getAnnotation[s]
|
||||
private static <A extends Annotation> Attribute.Compound getAttribute(Symbol annotated,
|
||||
Class<A> annoType) {
|
||||
String name = annoType.getName();
|
||||
|
||||
for (Attribute.Compound anno : annotated.getRawAttributes())
|
||||
if (name.equals(anno.type.tsym.flatName().toString()))
|
||||
return anno;
|
||||
|
||||
return null;
|
||||
}
|
||||
// Helper to getAnnotation[s]
|
||||
private static <A extends Annotation> Attribute.Compound getAttributeOnClass(ClassSymbol annotated,
|
||||
Class<A> annoType) {
|
||||
boolean inherited = annoType.isAnnotationPresent(Inherited.class);
|
||||
A result = null;
|
||||
Attribute.Compound result = null;
|
||||
while (annotated.name != annotated.name.table.names.java_lang_Object) {
|
||||
result = getAnnotation((Symbol)annotated, annoType);
|
||||
result = getAttribute(annotated, annoType);
|
||||
if (result != null || !inherited)
|
||||
break;
|
||||
Type sup = annotated.getSuperclass();
|
||||
@ -132,6 +145,188 @@ public class JavacElements implements Elements {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal-use utility that creates a runtime view of
|
||||
* annotations. This is the implementation of
|
||||
* Element.getAnnotations(Class).
|
||||
*/
|
||||
public static <A extends Annotation> A[] getAnnotations(Symbol annotated,
|
||||
Class<A> annoType) {
|
||||
if (!annoType.isAnnotation())
|
||||
throw new IllegalArgumentException("Not an annotation type: "
|
||||
+ annoType);
|
||||
// If annoType does not declare a container this is equivalent to wrapping
|
||||
// getAnnotation(...) in an array.
|
||||
Class <? extends Annotation> containerType = getContainer(annoType);
|
||||
if (containerType == null) {
|
||||
A res = getAnnotation(annotated, annoType);
|
||||
int size;
|
||||
if (res == null) {
|
||||
size = 0;
|
||||
} else {
|
||||
size = 1;
|
||||
}
|
||||
@SuppressWarnings("unchecked") // annoType is the Class for A
|
||||
A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
|
||||
if (res != null)
|
||||
arr[0] = res;
|
||||
return arr;
|
||||
}
|
||||
|
||||
// So we have a containing type
|
||||
String name = annoType.getName();
|
||||
String annoTypeName = annoType.getSimpleName();
|
||||
String containerTypeName = containerType.getSimpleName();
|
||||
int directIndex = -1, containerIndex = -1;
|
||||
Attribute.Compound direct = null, container = null;
|
||||
Attribute.Compound[] rawAttributes = annotated.getRawAttributes().toArray(new Attribute.Compound[0]);
|
||||
|
||||
// Find directly present annotations
|
||||
for (int i = 0; i < rawAttributes.length; i++) {
|
||||
if (annoTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
|
||||
directIndex = i;
|
||||
direct = rawAttributes[i];
|
||||
} else if(containerTypeName != null &&
|
||||
containerTypeName.equals(rawAttributes[i].type.tsym.flatName().toString())) {
|
||||
containerIndex = i;
|
||||
container = rawAttributes[i];
|
||||
}
|
||||
}
|
||||
// Deal with inherited annotations
|
||||
if (annotated.kind == Kinds.TYP &&
|
||||
(annotated instanceof ClassSymbol)) {
|
||||
ClassSymbol s = (ClassSymbol)annotated;
|
||||
if (direct == null && container == null) {
|
||||
direct = getAttributeOnClass(s, annoType);
|
||||
container = getAttributeOnClass(s, containerType);
|
||||
|
||||
// both are inherited and found, put container last
|
||||
if (direct != null && container != null) {
|
||||
directIndex = 0;
|
||||
containerIndex = 1;
|
||||
} else if (direct != null) {
|
||||
directIndex = 0;
|
||||
} else {
|
||||
containerIndex = 0;
|
||||
}
|
||||
} else if (direct == null) {
|
||||
direct = getAttributeOnClass(s, annoType);
|
||||
if (direct != null)
|
||||
directIndex = containerIndex + 1;
|
||||
} else if (container == null) {
|
||||
container = getAttributeOnClass(s, containerType);
|
||||
if (container != null)
|
||||
containerIndex = directIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Pack them in an array
|
||||
Attribute[] contained0 = new Attribute[0];
|
||||
if (container != null)
|
||||
contained0 = unpackAttributes(container);
|
||||
ListBuffer<Attribute.Compound> compounds = ListBuffer.lb();
|
||||
for (Attribute a : contained0)
|
||||
if (a instanceof Attribute.Compound)
|
||||
compounds = compounds.append((Attribute.Compound)a);
|
||||
Attribute.Compound[] contained = compounds.toArray(new Attribute.Compound[0]);
|
||||
|
||||
int size = (direct == null ? 0 : 1) + contained.length;
|
||||
@SuppressWarnings("unchecked") // annoType is the Class for A
|
||||
A[] arr = (A[])java.lang.reflect.Array.newInstance(annoType, size);
|
||||
|
||||
// if direct && container, which is first?
|
||||
int insert = -1;
|
||||
int length = arr.length;
|
||||
if (directIndex >= 0 && containerIndex >= 0) {
|
||||
if (directIndex < containerIndex) {
|
||||
arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
|
||||
insert = 1;
|
||||
} else {
|
||||
arr[arr.length - 1] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
|
||||
insert = 0;
|
||||
length--;
|
||||
}
|
||||
} else if (directIndex >= 0) {
|
||||
arr[0] = AnnotationProxyMaker.generateAnnotation(direct, annoType);
|
||||
return arr;
|
||||
} else {
|
||||
// Only container
|
||||
insert = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i + insert < length; i++)
|
||||
arr[insert + i] = AnnotationProxyMaker.generateAnnotation(contained[i], annoType);
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
// Needed to unpack the runtime view of containing annotations
|
||||
private static final Class<? extends Annotation> CONTAINED_BY_CLASS = initContainedBy();
|
||||
private static final Method VALUE_ELEMENT_METHOD = initValueElementMethod();
|
||||
|
||||
private static Class<? extends Annotation> initContainedBy() {
|
||||
try {
|
||||
@SuppressWarnings("unchecked") // java.lang.annotation.ContainedBy extends Annotation by being an annotation type
|
||||
Class<? extends Annotation> c = (Class)Class.forName("java.lang.annotation.ContainedBy");
|
||||
return c;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
} catch (SecurityException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private static Method initValueElementMethod() {
|
||||
if (CONTAINED_BY_CLASS == null)
|
||||
return null;
|
||||
|
||||
Method m = null;
|
||||
try {
|
||||
m = CONTAINED_BY_CLASS.getMethod("value");
|
||||
if (m != null)
|
||||
m.setAccessible(true);
|
||||
return m;
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to getAnnotations
|
||||
private static Class<? extends Annotation> getContainer(Class<? extends Annotation> annoType) {
|
||||
// Since we can not refer to java.lang.annotation.ContainedBy until we are
|
||||
// bootstrapping with java 8 we need to get the ContainedBy annotation using
|
||||
// reflective invocations instead of just using its type and element method.
|
||||
if (CONTAINED_BY_CLASS != null &&
|
||||
VALUE_ELEMENT_METHOD != null) {
|
||||
// Get the ContainedBy instance on the annotations declaration
|
||||
Annotation containedBy = (Annotation)annoType.getAnnotation(CONTAINED_BY_CLASS);
|
||||
if (containedBy != null) {
|
||||
try {
|
||||
// Get the value element, it should be a class
|
||||
// indicating the containing annotation type
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> containerType = (Class)VALUE_ELEMENT_METHOD.invoke(containedBy);
|
||||
if (containerType == null)
|
||||
return null;
|
||||
|
||||
return containerType;
|
||||
} catch (ClassCastException e) {
|
||||
return null;
|
||||
} catch (IllegalAccessException e) {
|
||||
return null;
|
||||
} catch (InvocationTargetException e ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Helper to getAnnotations
|
||||
private static Attribute[] unpackAttributes(Attribute.Compound container) {
|
||||
// We now have an instance of the container,
|
||||
// unpack it returning an instance of the
|
||||
// contained type or null
|
||||
return ((Attribute.Array)container.member(container.type.tsym.name.table.names.value)).values;
|
||||
}
|
||||
|
||||
public PackageSymbol getPackageElement(CharSequence name) {
|
||||
String strName = name.toString();
|
||||
@ -238,8 +433,10 @@ public class JavacElements implements Elements {
|
||||
tree.accept(vis);
|
||||
if (vis.result == null)
|
||||
return null;
|
||||
|
||||
List<Attribute.Compound> annos = sym.getRawAttributes();
|
||||
return matchAnnoToTree(cast(Attribute.Compound.class, findme),
|
||||
sym.getAnnotationMirrors(),
|
||||
annos,
|
||||
vis.result);
|
||||
}
|
||||
|
||||
@ -442,7 +639,7 @@ public class JavacElements implements Elements {
|
||||
*/
|
||||
public List<Attribute.Compound> getAllAnnotationMirrors(Element e) {
|
||||
Symbol sym = cast(Symbol.class, e);
|
||||
List<Attribute.Compound> annos = sym.getAnnotationMirrors();
|
||||
List<Attribute.Compound> annos = sym.getRawAttributes();
|
||||
while (sym.getKind() == ElementKind.CLASS) {
|
||||
Type sup = ((ClassSymbol) sym).getSuperclass();
|
||||
if (!sup.hasTag(CLASS) || sup.isErroneous() ||
|
||||
@ -451,7 +648,8 @@ public class JavacElements implements Elements {
|
||||
}
|
||||
sym = sup.tsym;
|
||||
List<Attribute.Compound> oldAnnos = annos;
|
||||
for (Attribute.Compound anno : sym.getAnnotationMirrors()) {
|
||||
List<Attribute.Compound> newAnnos = sym.getRawAttributes();
|
||||
for (Attribute.Compound anno : newAnnos) {
|
||||
if (isInherited(anno.type) &&
|
||||
!containsAnnoOfType(oldAnnos, anno.type)) {
|
||||
annos = annos.prepend(anno);
|
||||
@ -465,11 +663,7 @@ public class JavacElements implements Elements {
|
||||
* Tests whether an annotation type is @Inherited.
|
||||
*/
|
||||
private boolean isInherited(Type annotype) {
|
||||
for (Attribute.Compound anno : annotype.tsym.getAnnotationMirrors()) {
|
||||
if (anno.type.tsym == syms.inheritedType.tsym)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return annotype.tsym.attribute(syms.inheritedType.tsym) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -148,6 +148,56 @@ public interface Element {
|
||||
*/
|
||||
<A extends Annotation> A getAnnotation(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns an array of all of this element's annotation for the
|
||||
* specified type if such annotations are present, else an empty
|
||||
* array. The annotation may be either inherited or directly
|
||||
* present on this element. This method will look through a container
|
||||
* annotation (if present) if the supplied annotation type is
|
||||
* repeatable.
|
||||
*
|
||||
* <p> The annotations returned by this method could contain an element
|
||||
* whose value is of type {@code Class}.
|
||||
* This value cannot be returned directly: information necessary to
|
||||
* locate and load a class (such as the class loader to use) is
|
||||
* not available, and the class might not be loadable at all.
|
||||
* Attempting to read a {@code Class} object by invoking the relevant
|
||||
* method on the returned annotation
|
||||
* will result in a {@link MirroredTypeException},
|
||||
* from which the corresponding {@link TypeMirror} may be extracted.
|
||||
* Similarly, attempting to read a {@code Class[]}-valued element
|
||||
* will result in a {@link MirroredTypesException}.
|
||||
*
|
||||
* <blockquote>
|
||||
* <i>Note:</i> This method is unlike others in this and related
|
||||
* interfaces. It operates on runtime reflective information —
|
||||
* representations of annotation types currently loaded into the
|
||||
* VM — rather than on the representations defined by and used
|
||||
* throughout these interfaces. Consequently, calling methods on
|
||||
* the returned annotation object can throw many of the exceptions
|
||||
* that can be thrown when calling methods on an annotation object
|
||||
* returned by core reflection. This method is intended for
|
||||
* callers that are written to operate on a known, fixed set of
|
||||
* annotation types.
|
||||
* </blockquote>
|
||||
*
|
||||
* @param <A> the annotation type
|
||||
* @param annotationType the {@code Class} object corresponding to
|
||||
* the annotation type
|
||||
* @return this element's annotations for the specified annotation
|
||||
* type if present on this element, else an empty array
|
||||
*
|
||||
* @see #getAnnotationMirrors()
|
||||
* @see #getAnnotation()
|
||||
* @see java.lang.reflect.AnnotatedElement#getAnnotations
|
||||
* @see EnumConstantNotPresentException
|
||||
* @see AnnotationTypeMismatchException
|
||||
* @see IncompleteAnnotationException
|
||||
* @see MirroredTypeException
|
||||
* @see MirroredTypesException
|
||||
*/
|
||||
<A extends Annotation> A[] getAnnotations(Class<A> annotationType);
|
||||
|
||||
/**
|
||||
* Returns the modifiers of this element, excluding annotations.
|
||||
* Implicit modifiers, such as the {@code public} and {@code static}
|
||||
|
Loading…
x
Reference in New Issue
Block a user