Selective backport of annotation retrieval refinements (from 5.0.5)
In particular AnnotationTypeFilter's ignoring of standard Java interfaces, AnnotationUtils.clearCache() and a few extra common classes in ClassUtils. Issue: SPR-16667 Issue: SPR-16675
This commit is contained in:
@@ -29,6 +29,7 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -240,7 +241,6 @@ public class AnnotatedElementUtils {
|
||||
|
||||
return Boolean.TRUE.equals(
|
||||
searchWithGetSemantics(element, annotationType, annotationName, new SimpleAnnotationProcessor<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
|
||||
return (metaDepth > 0 ? Boolean.TRUE : CONTINUE);
|
||||
@@ -270,7 +270,6 @@ public class AnnotatedElementUtils {
|
||||
if (element.isAnnotationPresent(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, null, alwaysTrueAnnotationProcessor));
|
||||
}
|
||||
|
||||
@@ -615,7 +614,6 @@ public class AnnotatedElementUtils {
|
||||
if (element.isAnnotationPresent(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Boolean.TRUE.equals(searchWithFindSemantics(element, annotationType, null, alwaysTrueAnnotationProcessor));
|
||||
}
|
||||
|
||||
@@ -873,8 +871,8 @@ public class AnnotatedElementUtils {
|
||||
* @param processor the processor to delegate to
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
*/
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Processor<T> processor) {
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType, String annotationName, Processor<T> processor) {
|
||||
|
||||
return searchWithGetSemantics(element, annotationType, annotationName, null, processor);
|
||||
}
|
||||
@@ -893,12 +891,13 @@ public class AnnotatedElementUtils {
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
* @since 4.3
|
||||
*/
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Class<? extends Annotation> containerType, Processor<T> processor) {
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType, String annotationName,
|
||||
Class<? extends Annotation> containerType, Processor<T> processor) {
|
||||
|
||||
try {
|
||||
return searchWithGetSemantics(element, annotationType, annotationName, containerType, processor,
|
||||
new HashSet<AnnotatedElement>(), 0);
|
||||
return searchWithGetSemantics(element, annotationType, annotationName,
|
||||
containerType, processor, new HashSet<AnnotatedElement>(), 0);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
|
||||
@@ -923,8 +922,9 @@ public class AnnotatedElementUtils {
|
||||
* @param metaDepth the meta-depth of the annotation
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
*/
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Class<? extends Annotation> containerType, Processor<T> processor,
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType, String annotationName,
|
||||
Class<? extends Annotation> containerType, Processor<T> processor,
|
||||
Set<AnnotatedElement> visited, int metaDepth) {
|
||||
|
||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||
@@ -939,7 +939,7 @@ public class AnnotatedElementUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
|
||||
if (element instanceof Class) { // otherwise getAnnotations does not return anything new
|
||||
List<Annotation> inheritedAnnotations = new ArrayList<Annotation>();
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
if (!declaredAnnotations.contains(annotation)) {
|
||||
@@ -986,9 +986,9 @@ public class AnnotatedElementUtils {
|
||||
* @since 4.2
|
||||
*/
|
||||
private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement element,
|
||||
List<Annotation> annotations, Class<? extends Annotation> annotationType, String annotationName,
|
||||
Class<? extends Annotation> containerType, Processor<T> processor, Set<AnnotatedElement> visited,
|
||||
int metaDepth) {
|
||||
List<Annotation> annotations, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Class<? extends Annotation> containerType,
|
||||
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
|
||||
|
||||
// Search in annotations
|
||||
for (Annotation annotation : annotations) {
|
||||
@@ -1054,7 +1054,8 @@ public class AnnotatedElementUtils {
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
* @since 4.2
|
||||
*/
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType,
|
||||
String annotationName, Processor<T> processor) {
|
||||
|
||||
return searchWithFindSemantics(element, annotationType, annotationName, null, processor);
|
||||
@@ -1074,8 +1075,9 @@ public class AnnotatedElementUtils {
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
* @since 4.3
|
||||
*/
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Class<? extends Annotation> containerType, Processor<T> processor) {
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType, String annotationName,
|
||||
Class<? extends Annotation> containerType, Processor<T> processor) {
|
||||
|
||||
if (containerType != null && !processor.aggregates()) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -1083,8 +1085,8 @@ public class AnnotatedElementUtils {
|
||||
}
|
||||
|
||||
try {
|
||||
return searchWithFindSemantics(
|
||||
element, annotationType, annotationName, containerType, processor, new HashSet<AnnotatedElement>(), 0);
|
||||
return searchWithFindSemantics(element, annotationType, annotationName,
|
||||
containerType, processor, new HashSet<AnnotatedElement>(), 0);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
|
||||
@@ -1120,18 +1122,49 @@ public class AnnotatedElementUtils {
|
||||
try {
|
||||
// Locally declared annotations (ignoring @Inherited)
|
||||
Annotation[] annotations = element.getDeclaredAnnotations();
|
||||
List<T> aggregatedResults = (processor.aggregates() ? new ArrayList<T>() : null);
|
||||
if (annotations.length > 0) {
|
||||
List<T> aggregatedResults = (processor.aggregates() ? new ArrayList<T>() : null);
|
||||
|
||||
// Search in local annotations
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
|
||||
if (currentAnnotationType == annotationType ||
|
||||
currentAnnotationType.getName().equals(annotationName) ||
|
||||
processor.alwaysProcesses()) {
|
||||
T result = processor.process(element, annotation, metaDepth);
|
||||
// Search in local annotations
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
|
||||
if (currentAnnotationType == annotationType ||
|
||||
currentAnnotationType.getName().equals(annotationName) ||
|
||||
processor.alwaysProcesses()) {
|
||||
T result = processor.process(element, annotation, metaDepth);
|
||||
if (result != null) {
|
||||
if (aggregatedResults != null && metaDepth == 0) {
|
||||
aggregatedResults.add(result);
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Repeatable annotations in container?
|
||||
else if (currentAnnotationType == containerType) {
|
||||
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
|
||||
T result = processor.process(element, contained, metaDepth);
|
||||
if (aggregatedResults != null && result != null) {
|
||||
// No need to post-process since repeatable annotations within a
|
||||
// container cannot be composed annotations.
|
||||
aggregatedResults.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively search in meta-annotations
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
|
||||
T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth + 1);
|
||||
if (result != null) {
|
||||
if (processor.aggregates() && metaDepth == 0) {
|
||||
processor.postProcess(currentAnnotationType, annotation, result);
|
||||
if (aggregatedResults != null && metaDepth == 0) {
|
||||
aggregatedResults.add(result);
|
||||
}
|
||||
else {
|
||||
@@ -1139,60 +1172,36 @@ public class AnnotatedElementUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Repeatable annotations in container?
|
||||
else if (currentAnnotationType == containerType) {
|
||||
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
|
||||
T result = processor.process(element, contained, metaDepth);
|
||||
if (result != null) {
|
||||
// No need to post-process since repeatable annotations within a
|
||||
// container cannot be composed annotations.
|
||||
aggregatedResults.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search in meta annotations on local annotations
|
||||
for (Annotation annotation : annotations) {
|
||||
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
|
||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
|
||||
T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth + 1);
|
||||
if (result != null) {
|
||||
processor.postProcess(currentAnnotationType, annotation, result);
|
||||
if (processor.aggregates() && metaDepth == 0) {
|
||||
aggregatedResults.add(result);
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(aggregatedResults)) {
|
||||
// Prepend to support top-down ordering within class hierarchies
|
||||
processor.getAggregatedResults().addAll(0, aggregatedResults);
|
||||
}
|
||||
}
|
||||
|
||||
if (processor.aggregates()) {
|
||||
// Prepend to support top-down ordering within class hierarchies
|
||||
processor.getAggregatedResults().addAll(0, aggregatedResults);
|
||||
}
|
||||
|
||||
if (element instanceof Method) {
|
||||
Method method = (Method) element;
|
||||
T result;
|
||||
|
||||
// Search on possibly bridged method
|
||||
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
T result = searchWithFindSemantics(resolvedMethod, annotationType, annotationName, containerType,
|
||||
processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
if (resolvedMethod != method) {
|
||||
result = searchWithFindSemantics(resolvedMethod, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Search on methods in interfaces declared locally
|
||||
Class<?>[] ifcs = method.getDeclaringClass().getInterfaces();
|
||||
result = searchOnInterfaces(method, annotationType, annotationName, containerType, processor,
|
||||
visited, metaDepth, ifcs);
|
||||
if (result != null) {
|
||||
return result;
|
||||
if (ifcs.length > 0) {
|
||||
result = searchOnInterfaces(method, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth, ifcs);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Search on methods in class hierarchy and interface hierarchy
|
||||
@@ -1202,7 +1211,6 @@ public class AnnotatedElementUtils {
|
||||
if (clazz == null || Object.class == clazz) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
|
||||
Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
|
||||
@@ -1215,10 +1223,9 @@ public class AnnotatedElementUtils {
|
||||
catch (NoSuchMethodException ex) {
|
||||
// No equivalent method found
|
||||
}
|
||||
|
||||
// Search on interfaces declared on superclass
|
||||
result = searchOnInterfaces(method, annotationType, annotationName, containerType, processor,
|
||||
visited, metaDepth, clazz.getInterfaces());
|
||||
result = searchOnInterfaces(method, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth, clazz.getInterfaces());
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
@@ -1229,8 +1236,8 @@ public class AnnotatedElementUtils {
|
||||
|
||||
// Search on interfaces
|
||||
for (Class<?> ifc : clazz.getInterfaces()) {
|
||||
T result = searchWithFindSemantics(ifc, annotationType, annotationName, containerType,
|
||||
processor, visited, metaDepth);
|
||||
T result = searchWithFindSemantics(ifc, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
@@ -1239,8 +1246,8 @@ public class AnnotatedElementUtils {
|
||||
// Search on superclass
|
||||
Class<?> superclass = clazz.getSuperclass();
|
||||
if (superclass != null && Object.class != superclass) {
|
||||
T result = searchWithFindSemantics(superclass, annotationType, annotationName, containerType,
|
||||
processor, visited, metaDepth);
|
||||
T result = searchWithFindSemantics(superclass, annotationType, annotationName,
|
||||
containerType, processor, visited, metaDepth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -145,17 +145,17 @@ public abstract class AnnotationUtils {
|
||||
* <p>Note that this method supports only a single level of meta-annotations.
|
||||
* For support for arbitrary levels of meta-annotations, use one of the
|
||||
* {@code find*()} methods instead.
|
||||
* @param ann the Annotation to check
|
||||
* @param annotation the Annotation to check
|
||||
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
|
||||
* @return the first matching annotation, or {@code null} if not found
|
||||
* @since 4.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <A extends Annotation> A getAnnotation(Annotation ann, Class<A> annotationType) {
|
||||
if (annotationType.isInstance(ann)) {
|
||||
return synthesizeAnnotation((A) ann);
|
||||
public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType) {
|
||||
if (annotationType.isInstance(annotation)) {
|
||||
return synthesizeAnnotation((A) annotation);
|
||||
}
|
||||
Class<? extends Annotation> annotatedElement = ann.annotationType();
|
||||
Class<? extends Annotation> annotatedElement = annotation.annotationType();
|
||||
try {
|
||||
return synthesizeAnnotation(annotatedElement.getAnnotation(annotationType), annotatedElement);
|
||||
}
|
||||
@@ -568,7 +568,6 @@ public abstract class AnnotationUtils {
|
||||
if (result == null) {
|
||||
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||
result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);
|
||||
|
||||
if (result == null) {
|
||||
result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());
|
||||
}
|
||||
@@ -603,10 +602,10 @@ public abstract class AnnotationUtils {
|
||||
|
||||
private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class<?>... ifcs) {
|
||||
A annotation = null;
|
||||
for (Class<?> iface : ifcs) {
|
||||
if (isInterfaceWithAnnotatedMethods(iface)) {
|
||||
for (Class<?> ifc : ifcs) {
|
||||
if (isInterfaceWithAnnotatedMethods(ifc)) {
|
||||
try {
|
||||
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
|
||||
Method equivalentMethod = ifc.getMethod(method.getName(), method.getParameterTypes());
|
||||
annotation = getAnnotation(equivalentMethod, annotationType);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
@@ -620,13 +619,13 @@ public abstract class AnnotationUtils {
|
||||
return annotation;
|
||||
}
|
||||
|
||||
static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
|
||||
Boolean found = annotatedInterfaceCache.get(iface);
|
||||
static boolean isInterfaceWithAnnotatedMethods(Class<?> ifc) {
|
||||
Boolean found = annotatedInterfaceCache.get(ifc);
|
||||
if (found != null) {
|
||||
return found;
|
||||
}
|
||||
found = Boolean.FALSE;
|
||||
for (Method ifcMethod : iface.getMethods()) {
|
||||
for (Method ifcMethod : ifc.getMethods()) {
|
||||
try {
|
||||
if (ifcMethod.getAnnotations().length > 0) {
|
||||
found = Boolean.TRUE;
|
||||
@@ -637,7 +636,7 @@ public abstract class AnnotationUtils {
|
||||
handleIntrospectionFailure(ifcMethod, ex);
|
||||
}
|
||||
}
|
||||
annotatedInterfaceCache.put(iface, found);
|
||||
annotatedInterfaceCache.put(ifc, found);
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -1286,15 +1285,12 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
Object value = attributes.get(attributeName);
|
||||
boolean valuePresent = (value != null && !(value instanceof DefaultValueHolder));
|
||||
|
||||
for (String aliasedAttributeName : aliasMap.get(attributeName)) {
|
||||
if (valuesAlreadyReplaced.contains(aliasedAttributeName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object aliasedValue = attributes.get(aliasedAttributeName);
|
||||
boolean aliasPresent = (aliasedValue != null && !(aliasedValue instanceof DefaultValueHolder));
|
||||
|
||||
// Something to validate or replace with an alias?
|
||||
if (valuePresent || aliasPresent) {
|
||||
if (valuePresent && aliasPresent) {
|
||||
@@ -1919,6 +1915,20 @@ public abstract class AnnotationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the internal annotation metadata cache.
|
||||
* @since 4.3.15
|
||||
*/
|
||||
public static void clearCache() {
|
||||
findAnnotationCache.clear();
|
||||
metaPresentCache.clear();
|
||||
annotatedInterfaceCache.clear();
|
||||
synthesizableCache.clear();
|
||||
attributeAliasesCache.clear();
|
||||
attributeMethodsCache.clear();
|
||||
aliasDescriptorCache.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cache key for the AnnotatedElement cache.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,7 +70,9 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
|
||||
* @param considerMetaAnnotations whether to also match on meta-annotations
|
||||
* @param considerInterfaces whether to also match interfaces
|
||||
*/
|
||||
public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
|
||||
public AnnotationTypeFilter(
|
||||
Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
|
||||
|
||||
super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces);
|
||||
this.annotationType = annotationType;
|
||||
this.considerMetaAnnotations = considerMetaAnnotations;
|
||||
@@ -99,6 +101,11 @@ public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter
|
||||
return false;
|
||||
}
|
||||
else if (typeName.startsWith("java")) {
|
||||
if (!this.annotationType.getName().startsWith("java")) {
|
||||
// Standard Java types do not have non-standard annotations on them ->
|
||||
// skip any load attempt, in particular for Java language interfaces.
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
|
||||
return ((this.considerMetaAnnotations ? AnnotationUtils.getAnnotation(clazz, this.annotationType) :
|
||||
|
||||
@@ -112,7 +112,7 @@ public abstract class ClassUtils {
|
||||
registerCommonClasses(entry.getKey());
|
||||
}
|
||||
|
||||
Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(32);
|
||||
Set<Class<?>> primitiveTypes = new HashSet<Class<?>>(64);
|
||||
primitiveTypes.addAll(primitiveWrapperTypeMap.values());
|
||||
primitiveTypes.addAll(Arrays.asList(new Class<?>[] {
|
||||
boolean[].class, byte[].class, char[].class, double[].class,
|
||||
@@ -125,9 +125,10 @@ public abstract class ClassUtils {
|
||||
registerCommonClasses(Boolean[].class, Byte[].class, Character[].class, Double[].class,
|
||||
Float[].class, Integer[].class, Long[].class, Short[].class);
|
||||
registerCommonClasses(Number.class, Number[].class, String.class, String[].class,
|
||||
Object.class, Object[].class, Class.class, Class[].class);
|
||||
Class.class, Class[].class, Object.class, Object[].class);
|
||||
registerCommonClasses(Throwable.class, Exception.class, RuntimeException.class,
|
||||
Error.class, StackTraceElement.class, StackTraceElement[].class);
|
||||
registerCommonClasses(Enum.class, Iterable.class, Cloneable.class, Comparable.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user