src/share/classes/java/lang/Class.java
Print this page
*** 46,55 ****
--- 46,56 ----
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
+ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
*** 2316,2330 ****
--- 2317,2334 ----
private static final Unsafe unsafe = Unsafe.getUnsafe();
// offset of Class.reflectionData instance field
private static final long reflectionDataOffset;
// offset of Class.annotationType instance field
private static final long annotationTypeOffset;
+ // offset of Class.annotationData instance field
+ private static final long annotationDataOffset;
static {
Field[] fields = Class.class.getDeclaredFields0(false); // bypass caches
reflectionDataOffset = objectFieldOffset(fields, "reflectionData");
annotationTypeOffset = objectFieldOffset(fields, "annotationType");
+ annotationDataOffset = objectFieldOffset(fields, "annotationData");
}
private static long objectFieldOffset(Field[] fields, String fieldName) {
Field field = searchFields(fields, fieldName);
if (field == null) {
*** 2342,2362 ****
static <T> boolean casAnnotationType(Class<?> clazz,
AnnotationType oldType,
AnnotationType newType) {
return unsafe.compareAndSwapObject(clazz, annotationTypeOffset, oldType, newType);
}
}
/**
* Reflection support.
*/
// Caches for certain reflective results
private static boolean useCaches = true;
// reflection data that might get invalidated when JVM TI RedefineClasses() is called
! static class ReflectionData<T> {
volatile Field[] declaredFields;
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Constructor<T>[] declaredConstructors;
--- 2346,2372 ----
static <T> boolean casAnnotationType(Class<?> clazz,
AnnotationType oldType,
AnnotationType newType) {
return unsafe.compareAndSwapObject(clazz, annotationTypeOffset, oldType, newType);
}
+
+ static <T> boolean casAnnotationData(Class<?> clazz,
+ AnnotationData oldData,
+ AnnotationData newData) {
+ return unsafe.compareAndSwapObject(clazz, annotationDataOffset, oldData, newData);
+ }
}
/**
* Reflection support.
*/
// Caches for certain reflective results
private static boolean useCaches = true;
// reflection data that might get invalidated when JVM TI RedefineClasses() is called
! private static class ReflectionData<T> {
volatile Field[] declaredFields;
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Constructor<T>[] declaredConstructors;
*** 3199,3210 ****
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! initAnnotationsIfNecessary();
! return (A) annotations.get(annotationClass);
}
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
--- 3209,3219 ----
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! return (A) annotationData().annotations.get(annotationClass);
}
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*** 3221,3240 ****
*/
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! initAnnotationsIfNecessary();
! return AnnotationSupport.getMultipleAnnotations(annotations, annotationClass);
}
/**
* @since 1.5
*/
public Annotation[] getAnnotations() {
! initAnnotationsIfNecessary();
! return AnnotationParser.toArray(annotations);
}
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.8
--- 3230,3247 ----
*/
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! return AnnotationSupport.getMultipleAnnotations(annotationData().annotations, annotationClass);
}
/**
* @since 1.5
*/
public Annotation[] getAnnotations() {
! return AnnotationParser.toArray(annotationData().annotations);
}
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.8
*** 3242,3309 ****
@Override
@SuppressWarnings("unchecked")
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! initAnnotationsIfNecessary();
! return (A) declaredAnnotations.get(annotationClass);
}
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.8
*/
@Override
public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! initAnnotationsIfNecessary();
! return AnnotationSupport.getMultipleAnnotations(declaredAnnotations, annotationClass);
}
/**
* @since 1.5
*/
public Annotation[] getDeclaredAnnotations() {
! initAnnotationsIfNecessary();
! return AnnotationParser.toArray(declaredAnnotations);
}
// Annotations cache
! private transient Map<Class<? extends Annotation>, Annotation> annotations;
! private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
! // Value of classRedefinedCount when we last cleared the cached annotations and declaredAnnotations fields
! private transient int lastAnnotationsRedefinedCount = 0;
!
! // Clears cached values that might possibly have been obsoleted by
! // a class redefinition.
! private void clearAnnotationCachesOnClassRedefinition() {
! if (lastAnnotationsRedefinedCount != classRedefinedCount) {
! annotations = declaredAnnotations = null;
! lastAnnotationsRedefinedCount = classRedefinedCount;
}
}
! private synchronized void initAnnotationsIfNecessary() {
! clearAnnotationCachesOnClassRedefinition();
! if (annotations != null)
! return;
! declaredAnnotations = AnnotationParser.parseAnnotations(
! getRawAnnotations(), getConstantPool(), this);
Class<?> superClass = getSuperclass();
! if (superClass == null) {
! annotations = declaredAnnotations;
! } else {
! annotations = new HashMap<>();
! superClass.initAnnotationsIfNecessary();
! for (Map.Entry<Class<? extends Annotation>, Annotation> e : superClass.annotations.entrySet()) {
Class<? extends Annotation> annotationClass = e.getKey();
! if (AnnotationType.getInstance(annotationClass).isInherited())
annotations.put(annotationClass, e.getValue());
}
annotations.putAll(declaredAnnotations);
}
}
// Annotation types cache their internal (AnnotationType) form
@SuppressWarnings("UnusedDeclaration")
--- 3249,3348 ----
@Override
@SuppressWarnings("unchecked")
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! return (A) annotationData().declaredAnnotations.get(annotationClass);
}
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.8
*/
@Override
public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
! return AnnotationSupport.getMultipleAnnotations(annotationData().declaredAnnotations, annotationClass);
}
/**
* @since 1.5
*/
public Annotation[] getDeclaredAnnotations() {
! return AnnotationParser.toArray(annotationData().declaredAnnotations);
! }
!
! // annotation data that might get invalidated when JVM TI RedefineClasses() is called
! private static class AnnotationData {
! final Map<Class<? extends Annotation>, Annotation> annotations;
! final Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
!
! // Value of classRedefinedCount when we created this AnnotationData instance
! final int redefinedCount;
!
! AnnotationData(Map<Class<? extends Annotation>, Annotation> annotations,
! Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
! int redefinedCount) {
! this.annotations = annotations;
! this.declaredAnnotations = declaredAnnotations;
! this.redefinedCount = redefinedCount;
! }
}
// Annotations cache
! @SuppressWarnings("UnusedDeclaration")
! private volatile transient AnnotationData annotationData;
!
! private AnnotationData annotationData() {
! while (true) { // retry loop
! AnnotationData annotationData = this.annotationData;
! int classRedefinedCount = this.classRedefinedCount;
! if (annotationData != null &&
! annotationData.redefinedCount == classRedefinedCount) {
! return annotationData;
! }
! // null or stale annotationData -> optimistically create new instance
! AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount);
! // try to install it
! if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) {
! // successfully installed new AnnotationData
! return newAnnotationData;
! }
}
}
! private AnnotationData createAnnotationData(int classRedefinedCount) {
! Map<Class<? extends Annotation>, Annotation> declaredAnnotations =
! AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);
Class<?> superClass = getSuperclass();
! Map<Class<? extends Annotation>, Annotation> annotations = null;
! if (superClass != null) {
! Map<Class<? extends Annotation>, Annotation> superAnnotations =
! superClass.annotationData().annotations;
! for (Map.Entry<Class<? extends Annotation>, Annotation> e : superAnnotations.entrySet()) {
Class<? extends Annotation> annotationClass = e.getKey();
! if (AnnotationType.getInstance(annotationClass).isInherited()) {
! if (annotations == null) { // lazy construction
! annotations = new LinkedHashMap<>((Math.max(
! declaredAnnotations.size(),
! Math.min(12, declaredAnnotations.size() + superAnnotations.size())
! ) * 4 + 2) / 3
! );
! }
annotations.put(annotationClass, e.getValue());
}
+ }
+ }
+ if (annotations == null) {
+ // no inherited annotations -> share the Map with declaredAnnotations
+ annotations = declaredAnnotations;
+ } else {
+ // at least one inherited annotation -> declared may override inherited
annotations.putAll(declaredAnnotations);
}
+ return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount);
}
// Annotation types cache their internal (AnnotationType) form
@SuppressWarnings("UnusedDeclaration")