JUNEAU-169 Dynamic annotations.
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
index 9ba7428..1cb14a4 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
@@ -43,8 +43,8 @@
public RdfBeanPropertyMeta(BeanPropertyMeta bpm, RdfMetaProvider mp) {
super(bpm);
- List<Rdf> rdfs = bpm.getAllAnnotations(Rdf.class, mp);
- List<RdfSchema> schemas = bpm.getAllAnnotations(RdfSchema.class, mp);
+ List<Rdf> rdfs = bpm.getAllAnnotations(Rdf.class);
+ List<RdfSchema> schemas = bpm.getAllAnnotations(RdfSchema.class);
for (Rdf rdf : rdfs) {
if (collectionFormat == RdfCollectionFormat.DEFAULT)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index c61fc58..6aff3ce 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -2230,7 +2230,7 @@
if (ci.isChildOf(PojoSwap.class))
lpf.add(castOrCreate(PojoSwap.class, ci.inner()));
else if (ci.isChildOf(Surrogate.class))
- lpf.addAll(SurrogateSwap.findPojoSwaps(ci.inner()));
+ lpf.addAll(SurrogateSwap.findPojoSwaps(ci.inner(), this));
else
throw new FormattedRuntimeException("Invalid class {0} specified in BeanContext.pojoSwaps property. Must be a subclass of PojoSwap or Surrogate.", ci.inner());
} else if (o instanceof PojoSwap) {
@@ -3011,29 +3011,252 @@
// MetaProvider methods
//-----------------------------------------------------------------------------------------------------------------
+ private static final boolean DISABLE_ANNOTATION_CACHING = ! Boolean.getBoolean("juneau.disableAnnotationCaching");
+
+ private TwoKeyConcurrentHashMap<Class<?>,Class<? extends Annotation>,Optional<Annotation>> classAnnotationCache = new TwoKeyConcurrentHashMap<>();
+ private TwoKeyConcurrentHashMap<Class<?>,Class<? extends Annotation>,Optional<Annotation>> declaredClassAnnotationCache = new TwoKeyConcurrentHashMap<>();
+ private TwoKeyConcurrentHashMap<Method,Class<? extends Annotation>,Optional<Annotation>> methodAnnotationCache = new TwoKeyConcurrentHashMap<>();
+ private TwoKeyConcurrentHashMap<Field,Class<? extends Annotation>,Optional<Annotation>> fieldAnnotationCache = new TwoKeyConcurrentHashMap<>();
+ private TwoKeyConcurrentHashMap<Constructor<?>,Class<? extends Annotation>,Optional<Annotation>> constructorAnnotationCache = new TwoKeyConcurrentHashMap<>();
+
@Override /* MetaProvider */
public <A extends Annotation> A getAnnotation(Class<A> a, Class<?> c) {
- return a == null || c == null ? null : (A)annotations.findFirst(c, a).orElse(c.getAnnotation(a));
+ if (a == null || c == null)
+ return null;
+ if (DISABLE_ANNOTATION_CACHING)
+ return (A)annotations.findFirst(c, a).orElse(c.getAnnotation(a));
+ Optional<Annotation> aa = classAnnotationCache.get(c, a);
+ if (aa == null) {
+ aa = Optional.ofNullable((A)annotations.findFirst(c, a).orElse(c.getAnnotation(a)));
+ classAnnotationCache.put(c, a, aa);
+ }
+ return (A)aa.orElse(null);
+ }
+
+ /**
+ * Finds the specified annotation on the specified class.
+ *
+ * @param <A> The annotation type to find.
+ * @param a The annotation type to find.
+ * @param c The class to search on.
+ * @return The annotation, or <jk>null</jk> if not found.
+ */
+ public <A extends Annotation> A getAnnotation(Class<A> a, ClassInfo c) {
+ return getAnnotation(a, c == null ? null : c.inner());
}
@Override /* MetaProvider */
public <A extends Annotation> A getDeclaredAnnotation(Class<A> a, Class<?> c) {
- return a == null || c == null ? null : (A)annotations.findFirst(c, a).orElse(c.getAnnotation(a));
+ if (a == null || c == null)
+ return null;
+ if (DISABLE_ANNOTATION_CACHING)
+ return (A)annotations.findFirst(c, a).orElse(c.getDeclaredAnnotation(a));
+ Optional<Annotation> aa = declaredClassAnnotationCache.get(c, a);
+ if (aa == null) {
+ aa = Optional.ofNullable((A)annotations.findFirst(c, a).orElse(c.getDeclaredAnnotation(a)));
+ declaredClassAnnotationCache.put(c, a, aa);
+ }
+ return (A)aa.orElse(null);
+ }
+
+ /**
+ * Finds the specified declared annotation on the specified class.
+ *
+ * @param <A> The annotation type to find.
+ * @param a The annotation type to find.
+ * @param c The class to search on.
+ * @return The annotation, or <jk>null</jk> if not found.
+ */
+ public <A extends Annotation> A getDeclaredAnnotation(Class<A> a, ClassInfo c) {
+ return getDeclaredAnnotation(a, c == null ? null : c.inner());
}
@Override /* MetaProvider */
public <A extends Annotation> A getAnnotation(Class<A> a, Method m) {
- return a == null || m == null ? null : (A)annotations.findFirst(m, a).orElse(m.getAnnotation(a));
+ if (a == null || m == null)
+ return null;
+ if (DISABLE_ANNOTATION_CACHING)
+ return (A)annotations.findFirst(m, a).orElse(m.getAnnotation(a));
+ Optional<Annotation> aa = methodAnnotationCache.get(m, a);
+ if (aa == null) {
+ aa = Optional.ofNullable((A)annotations.findFirst(m, a).orElse(m.getAnnotation(a)));
+ methodAnnotationCache.put(m, a, aa);
+ }
+ return (A)aa.orElse(null);
+ }
+
+ /**
+ * Finds the specified annotation on the specified method.
+ *
+ * @param <A> The annotation type to find.
+ * @param a The annotation type to find.
+ * @param m The method to search on.
+ * @return The annotation, or <jk>null</jk> if not found.
+ */
+ public <A extends Annotation> A getAnnotation(Class<A> a, MethodInfo m) {
+ return getAnnotation(a, m == null ? null : m.inner());
}
@Override /* MetaProvider */
public <A extends Annotation> A getAnnotation(Class<A> a, Field f) {
- return a == null || f == null ? null : (A)annotations.findFirst(f, a).orElse(f.getAnnotation(a));
+ if (a == null || f == null)
+ return null;
+ if (DISABLE_ANNOTATION_CACHING)
+ return (A)annotations.findFirst(f, a).orElse(f.getAnnotation(a));
+ Optional<Annotation> aa = fieldAnnotationCache.get(f, a);
+ if (aa == null) {
+ aa = Optional.ofNullable((A)annotations.findFirst(f, a).orElse(f.getAnnotation(a)));
+ fieldAnnotationCache.put(f, a, aa);
+ }
+ return (A)aa.orElse(null);
+ }
+
+ /**
+ * Finds the specified annotation on the specified field.
+ *
+ * @param <A> The annotation type to find.
+ * @param a The annotation type to find.
+ * @param f The field to search on.
+ * @return The annotation, or <jk>null</jk> if not found.
+ */
+ public <A extends Annotation> A getAnnotation(Class<A> a, FieldInfo f) {
+ return getAnnotation(a, f == null ? null: f.inner());
}
@Override /* MetaProvider */
public <A extends Annotation> A getAnnotation(Class<A> a, Constructor<?> c) {
- return a == null || c == null ? null : (A)annotations.findFirst(c, a).orElse(c.getAnnotation(a));
+ if (a == null || c == null)
+ return null;
+ if (DISABLE_ANNOTATION_CACHING)
+ return (A)annotations.findFirst(c, a).orElse(c.getAnnotation(a));
+ Optional<Annotation> aa = constructorAnnotationCache.get(c, a);
+ if (aa == null) {
+ aa = Optional.ofNullable((A)annotations.findFirst(c, a).orElse(c.getAnnotation(a)));
+ constructorAnnotationCache.put(c, a, aa);
+ }
+ return (A)aa.orElse(null);
+ }
+
+ /**
+ * Finds the specified annotation on the specified constructor.
+ *
+ * @param <A> The annotation type to find.
+ * @param a The annotation type to find.
+ * @param c The constructor to search on.
+ * @return The annotation, or <jk>null</jk> if not found.
+ */
+ public <A extends Annotation> A getAnnotation(Class<A> a, ConstructorInfo c) {
+ return getAnnotation(a, c == null ? null : c.inner());
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param c The class being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified class.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, Class<?> c) {
+ return getAnnotation(a, c) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param c The class being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified class.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, ClassInfo c) {
+ return getAnnotation(a, c == null ? null : c.inner()) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param c The class being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified class.
+ */
+ public <A extends Annotation> boolean hasDeclaredAnnotation(Class<A> a, Class<?> c) {
+ return getDeclaredAnnotation(a, c) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getDeclaredAnnotation(a,c)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param c The class being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified class.
+ */
+ public <A extends Annotation> boolean hasDeclaredAnnotation(Class<A> a, ClassInfo c) {
+ return getDeclaredAnnotation(a, c == null ? null : c.inner()) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,m)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param m The method being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified method.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, Method m) {
+ return getAnnotation(a, m) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,m)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param m The method being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified method.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, MethodInfo m) {
+ return getAnnotation(a, m == null ? null : m.inner()) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,f)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param f The field being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified field.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, Field f) {
+ return getAnnotation(a, f) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,f)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param f The field being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified field.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, FieldInfo f) {
+ return getAnnotation(a, f == null ? null : f.inner()) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param c The constructor being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified constructor.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, Constructor<?> c) {
+ return getAnnotation(a, c) != null;
+ }
+
+ /**
+ * Returns <jk>true</jk> if <c>getAnnotation(a,c)</c> returns a non-null value.
+ *
+ * @param a The annotation being checked for.
+ * @param c The constructor being checked on.
+ * @return <jk>true</jk> if the annotation exists on the specified constructor.
+ */
+ public <A extends Annotation> boolean hasAnnotation(Class<A> a, ConstructorInfo c) {
+ return getAnnotation(a, c == null ? null : c.inner()) != null;
}
//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index 0f01aab..5945ada 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -233,11 +233,11 @@
}
constructor.setAccessible();
}
- if (x.hasAnnotation(Beanc.class)) {
+ if (ctx.hasAnnotation(Beanc.class, x)) {
if (constructor != null)
throw new BeanRuntimeException(c, "Multiple instances of '@Beanc' found.");
constructor = x;
- constructorArgs = split(x.getAnnotation(Beanc.class).properties());
+ constructorArgs = split(ctx.getAnnotation(Beanc.class, x).properties());
if (constructorArgs.length != x.getParamCount()) {
if (constructorArgs.length != 0)
throw new BeanRuntimeException(c, "Number of properties defined in '@Beanc' annotation does not match number of parameters in constructor.");
@@ -320,7 +320,7 @@
} else /* Use 'better' introspection */ {
- for (Field f : findBeanFields(c2, stopClass, fVis, filterProps)) {
+ for (Field f : findBeanFields(ctx, c2, stopClass, fVis, filterProps)) {
String name = findPropertyName(f, fixedBeanProps);
if (name != null) {
if (! normalProps.containsKey(name))
@@ -329,7 +329,7 @@
}
}
- List<BeanMethod> bms = findBeanMethods(c2, stopClass, mVis, fixedBeanProps, filterProps, propertyNamer, fluentSetters);
+ List<BeanMethod> bms = findBeanMethods(ctx, c2, stopClass, mVis, fixedBeanProps, filterProps, propertyNamer, fluentSetters);
// Iterate through all the getters.
for (BeanMethod bm : bms) {
@@ -345,7 +345,7 @@
if (m.getAnnotation(BeanProperty.class) == null && bpm.getter.getAnnotation(BeanProperty.class) != null)
m = bpm.getter; // @BeanProperty annotated method takes precedence.
- else if (m.getAnnotation(Beanp.class) == null && bpm.getter.getAnnotation(Beanp.class) != null)
+ else if (! ctx.hasAnnotation(Beanp.class, m) && ctx.hasAnnotation(Beanp.class, bpm.getter))
m = bpm.getter; // @Beanp annotated method takes precedence.
else if (m.getName().startsWith("is") && bpm.getter.getName().startsWith("get"))
@@ -510,8 +510,8 @@
private String findPropertyName(Field f, Set<String> fixedBeanProps) {
@SuppressWarnings("deprecation")
BeanProperty px = f.getAnnotation(BeanProperty.class);
- Beanp p = f.getAnnotation(Beanp.class);
- Name n = f.getAnnotation(Name.class);
+ Beanp p = ctx.getAnnotation(Beanp.class, f);
+ Name n = ctx.getAnnotation(Name.class, f);
String name = bpName(px, p, n);
if (isNotEmpty(name)) {
if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name))
@@ -633,7 +633,7 @@
* @param fixedBeanProps Only include methods whose properties are in this list.
* @param pn Use this property namer to determine property names from the method names.
*/
- static final List<BeanMethod> findBeanMethods(Class<?> c, Class<?> stopClass, Visibility v, Set<String> fixedBeanProps, Set<String> filterProps, PropertyNamer pn, boolean fluentSetters) {
+ static final List<BeanMethod> findBeanMethods(BeanContext ctx, Class<?> c, Class<?> stopClass, Visibility v, Set<String> fixedBeanProps, Set<String> filterProps, PropertyNamer pn, boolean fluentSetters) {
List<BeanMethod> l = new LinkedList<>();
for (ClassInfo c2 : findClasses(c, stopClass)) {
@@ -645,14 +645,14 @@
if (m.getParamCount() > 2)
continue;
- BeanIgnore bi = m.getAnnotation(BeanIgnore.class);
+ BeanIgnore bi = ctx.getAnnotation(BeanIgnore.class, m);
if (bi != null)
continue;
@SuppressWarnings("deprecation")
BeanProperty px = m.getAnnotation(BeanProperty.class);
- Beanp p = m.getAnnotation(Beanp.class);
- Name n2 = m.getAnnotation(Name.class);
+ Beanp p = ctx.getAnnotation(Beanp.class, m);
+ Name n2 = ctx.getAnnotation(Name.class, m);
if (! (m.isVisible(v) || px != null || p != null || n2 != null))
continue;
@@ -746,7 +746,7 @@
return l;
}
- static final Collection<Field> findBeanFields(Class<?> c, Class<?> stopClass, Visibility v, Set<String> filterProps) {
+ static final Collection<Field> findBeanFields(BeanContext ctx, Class<?> c, Class<?> stopClass, Visibility v, Set<String> filterProps) {
List<Field> l = new LinkedList<>();
for (ClassInfo c2 : findClasses(c, stopClass)) {
for (FieldInfo f : c2.getDeclaredFields()) {
@@ -757,8 +757,8 @@
@SuppressWarnings("deprecation")
BeanProperty px = f.getAnnotation(BeanProperty.class);
- Beanp p = f.getAnnotation(Beanp.class);
- Name n = f.getAnnotation(Name.class);
+ Beanp p = ctx.getAnnotation(Beanp.class, f);
+ Name n = ctx.getAnnotation(Name.class, f);
String bpName = bpName(px, p, n);
if (! (v.isVisible(f.inner()) || px != null || p != null))
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index 50c8fe0..56fb06c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -160,14 +160,14 @@
}
@SuppressWarnings("deprecation")
- boolean validate(BeanContext f, BeanRegistry parentBeanRegistry, Map<Class<?>,Class<?>[]> typeVarImpls, Set<String> bpro, Set<String> bpwo) throws Exception {
+ boolean validate(BeanContext bc, BeanRegistry parentBeanRegistry, Map<Class<?>,Class<?>[]> typeVarImpls, Set<String> bpro, Set<String> bpwo) throws Exception {
List<Class<?>> bdClasses = new ArrayList<>();
if (field == null && getter == null && setter == null)
return false;
- if (field == null && setter == null && f.isBeansRequireSettersForGetters() && ! isConstructorArg)
+ if (field == null && setter == null && bc.isBeansRequireSettersForGetters() && ! isConstructorArg)
return false;
canRead |= (field != null || getter != null);
@@ -175,11 +175,11 @@
if (innerField != null) {
BeanProperty px = innerField.getAnnotation(BeanProperty.class);
- Beanp p = innerField.getAnnotation(Beanp.class);
+ Beanp p = bc.getAnnotation(Beanp.class, innerField);
if (field != null || px != null || p != null) {
// Only use field type if it's a bean property or has @Beanp annotation.
// Otherwise, we want to infer the type from the getter or setter.
- rawTypeMeta = f.resolveClassMeta(px, p, innerField.getGenericType(), typeVarImpls);
+ rawTypeMeta = bc.resolveClassMeta(px, p, innerField.getGenericType(), typeVarImpls);
isUri |= (rawTypeMeta.isUri());
}
if (px != null) {
@@ -196,19 +196,19 @@
if (! p.wo().isEmpty())
writeOnly = Boolean.valueOf(p.wo());
}
- Swap s = innerField.getAnnotation(Swap.class);
+ Swap s = bc.getAnnotation(Swap.class, innerField);
if (s != null) {
swap = getPropertyPojoSwap(s);
}
- isUri |= innerField.isAnnotationPresent(org.apache.juneau.annotation.URI.class);
+ isUri |= bc.getAnnotation(org.apache.juneau.annotation.URI.class, innerField) != null;
}
if (getter != null) {
BeanProperty px = MethodInfo.of(getter).getAnnotation(BeanProperty.class);
- Beanp p = MethodInfo.of(getter).getAnnotation(Beanp.class);
+ Beanp p = bc.getAnnotation(Beanp.class, getter);
if (rawTypeMeta == null)
- rawTypeMeta = f.resolveClassMeta(px, p, getter.getGenericReturnType(), typeVarImpls);
- isUri |= (rawTypeMeta.isUri() || getter.isAnnotationPresent(org.apache.juneau.annotation.URI.class));
+ rawTypeMeta = bc.resolveClassMeta(px, p, getter.getGenericReturnType(), typeVarImpls);
+ isUri |= (rawTypeMeta.isUri() || bc.hasAnnotation(org.apache.juneau.annotation.URI.class, getter));
if (px != null) {
if (properties != null && ! px.properties().isEmpty())
properties = split(px.properties());
@@ -223,7 +223,7 @@
if (! p.wo().isEmpty())
writeOnly = Boolean.valueOf(p.wo());
}
- Swap s = getter.getAnnotation(Swap.class);
+ Swap s = bc.getAnnotation(Swap.class, getter);
if (s != null && swap == null) {
swap = getPropertyPojoSwap(s);
}
@@ -231,9 +231,9 @@
if (setter != null) {
BeanProperty px = MethodInfo.of(setter).getAnnotation(BeanProperty.class);
- Beanp p = MethodInfo.of(setter).getAnnotation(Beanp.class);
+ Beanp p = bc.getAnnotation(Beanp.class, setter);
if (rawTypeMeta == null)
- rawTypeMeta = f.resolveClassMeta(px, p, setter.getGenericParameterTypes()[0], typeVarImpls);
+ rawTypeMeta = bc.resolveClassMeta(px, p, setter.getGenericParameterTypes()[0], typeVarImpls);
isUri |= (rawTypeMeta.isUri() || setter.isAnnotationPresent(org.apache.juneau.annotation.URI.class));
if (px != null) {
if (swap == null)
@@ -253,7 +253,7 @@
if (! p.wo().isEmpty())
writeOnly = Boolean.valueOf(p.wo());
}
- Swap s = setter.getAnnotation(Swap.class);
+ Swap s = bc.getAnnotation(Swap.class, setter);
if (s != null && swap == null) {
swap = getPropertyPojoSwap(s);
}
@@ -1125,31 +1125,31 @@
*
* @param <A> The class to find annotations for.
* @param a The class to find annotations for.
- * @param mp The metadata provider for finding annotations.
* @return A list of annotations ordered in child-to-parent order. Never <jk>null</jk>.
*/
- public <A extends Annotation> List<A> getAllAnnotations(Class<A> a, MetaProvider mp) {
+ public <A extends Annotation> List<A> getAllAnnotations(Class<A> a) {
List<A> l = new LinkedList<>();
+ BeanContext bc = beanContext;
if (a == null)
return l;
if (field != null) {
- addIfNotNull(l, mp.getAnnotation(a, field));
- ClassInfo.of(field.getType()).appendAnnotations(l, a, mp);
+ addIfNotNull(l, bc.getAnnotation(a, field));
+ ClassInfo.of(field.getType()).appendAnnotations(l, a, bc);
}
if (getter != null) {
- addIfNotNull(l, mp.getAnnotation(a, getter));
- ClassInfo.of(getter.getReturnType()).appendAnnotations(l, a, mp);
+ addIfNotNull(l, bc.getAnnotation(a, getter));
+ ClassInfo.of(getter.getReturnType()).appendAnnotations(l, a, bc);
}
if (setter != null) {
- addIfNotNull(l, mp.getAnnotation(a, setter));
- ClassInfo.of(setter.getReturnType()).appendAnnotations(l, a, mp);
+ addIfNotNull(l, bc.getAnnotation(a, setter));
+ ClassInfo.of(setter.getReturnType()).appendAnnotations(l, a, bc);
}
if (extraKeys != null) {
- addIfNotNull(l, mp.getAnnotation(a, extraKeys));
- ClassInfo.of(extraKeys.getReturnType()).appendAnnotations(l, a, mp);
+ addIfNotNull(l, bc.getAnnotation(a, extraKeys));
+ ClassInfo.of(extraKeys.getReturnType()).appendAnnotations(l, a, bc);
}
- getBeanMeta().getClassMeta().getInfo().appendAnnotations(l, a, mp);
+ getBeanMeta().getClassMeta().getInfo().appendAnnotations(l, a, bc);
return l;
}
@@ -1158,16 +1158,16 @@
*
* @param <A> The class to find annotations for.
* @param a The class to find annotations for.
- * @param mp The metadata provider for finding annotations.
* @return A list of annotations ordered in child-to-parent order. Never <jk>null</jk>.
*/
- public <A extends Annotation> List<A> getAnnotations(Class<A> a, MetaProvider mp) {
+ public <A extends Annotation> List<A> getAnnotations(Class<A> a) {
List<A> l = new LinkedList<>();
+ BeanContext bc = beanContext;
if (a == null)
return l;
- addIfNotNull(l, mp.getAnnotation(a, field));
- addIfNotNull(l, mp.getAnnotation(a, getter));
- addIfNotNull(l, mp.getAnnotation(a, setter));
+ addIfNotNull(l, bc.getAnnotation(a, field));
+ addIfNotNull(l, bc.getAnnotation(a, getter));
+ addIfNotNull(l, bc.getAnnotation(a, setter));
return l;
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
index b643d3a..f39ba23 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanRegistry.java
@@ -89,7 +89,7 @@
addToMap(typeName, val);
}
} else {
- Bean b = ci.getAnnotation(Bean.class);
+ Bean b = ci.getAnnotation(Bean.class, beanContext);
if (b == null || b.typeName().isEmpty())
throw new BeanRuntimeException("Class ''{0}'' was passed to BeanRegistry but it doesn't have a @Bean(typeName) annotation defined.", c.getName());
addToMap(b.typeName(), beanContext.getClassMeta(c));
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
index 8301fb4..4cfd4b0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanTraverseSession.java
@@ -120,8 +120,6 @@
return null;
isBottom = false;
stack.add(new StackElement(stack.size(), attrName, o, cm));
- if (isDebug())
- getLogger().info(getStack(false));
set.put(o, o);
}
return cm;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index 550e82b..c0cd6f4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -351,6 +351,7 @@
ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps, Object example) {
this.innerClass = innerClass;
this.beanContext = beanContext;
+ BeanContext bc = beanContext;
this.implClass = implClass;
ClassInfo ici = ClassInfo.of(implClass);
@@ -534,15 +535,15 @@
}
if (beanFilter == null)
- beanFilter = findBeanFilter();
+ beanFilter = findBeanFilter(bc);
if (pojoSwaps != null)
this.pojoSwaps.addAll(Arrays.asList(pojoSwaps));
- if (beanContext != null)
- this.builderSwap = BuilderSwap.findSwapFromPojoClass(c, beanContext.getBeanConstructorVisibility(), beanContext.getBeanMethodVisibility());
+ if (bc != null)
+ this.builderSwap = BuilderSwap.findSwapFromPojoClass(c, bc.getBeanConstructorVisibility(), bc.getBeanMethodVisibility());
- findPojoSwaps(this.pojoSwaps);
+ findPojoSwaps(this.pojoSwaps, bc);
try {
@@ -578,7 +579,7 @@
BeanMeta newMeta = null;
try {
- newMeta = new BeanMeta(ClassMeta.this, beanContext, beanFilter, null);
+ newMeta = new BeanMeta(ClassMeta.this, bc, beanFilter, null);
notABeanReason = newMeta.notABeanReason;
// Always get these even if it's not a bean:
@@ -603,22 +604,22 @@
if (beanMeta != null)
dictionaryName = beanMeta.getDictionaryName();
- if (beanMeta != null && beanContext != null && beanContext.isUseInterfaceProxies() && innerClass.isInterface())
+ if (beanMeta != null && bc != null && bc.isUseInterfaceProxies() && innerClass.isInterface())
invocationHandler = new BeanProxyInvocationHandler<T>(beanMeta);
- Bean b = c.getAnnotation(Bean.class);
+ Bean b = bc == null ? null : bc.getAnnotation(Bean.class, c);
if (b != null) {
if (b.beanDictionary().length != 0)
- beanRegistry = new BeanRegistry(beanContext, null, b.beanDictionary());
+ beanRegistry = new BeanRegistry(bc, null, b.beanDictionary());
if (b.dictionary().length != 0)
- beanRegistry = new BeanRegistry(beanContext, null, b.dictionary());
+ beanRegistry = new BeanRegistry(bc, null, b.dictionary());
// This could be a non-bean POJO with a type name.
if (dictionaryName == null && ! b.typeName().isEmpty())
dictionaryName = b.typeName();
}
- Example e = c.getAnnotation(Example.class);
+ Example e = bc == null ? null : bc.getAnnotation(Example.class, c);
if (example == null && e != null && ! e.value().isEmpty())
example = e.value();
@@ -678,9 +679,9 @@
this.stringMutater = Mutaters.get(String.class, c);
}
- private BeanFilter findBeanFilter() {
+ private BeanFilter findBeanFilter(BeanContext bc) {
try {
- List<Bean> ba = info.getAnnotations(Bean.class);
+ List<Bean> ba = info.getAnnotations(Bean.class, bc);
if (! ba.isEmpty())
return new AnnotationBeanFilterBuilder(innerClass, ba).build();
} catch (Exception e) {
@@ -689,11 +690,11 @@
return null;
}
- private void findPojoSwaps(List<PojoSwap> l) {
- Swap swap = innerClass.getAnnotation(Swap.class);
+ private void findPojoSwaps(List<PojoSwap> l, BeanContext bc) {
+ Swap swap = bc == null ? null : bc.getAnnotation(Swap.class, innerClass);
if (swap != null)
l.add(createPojoSwap(swap));
- Swaps swaps = innerClass.getAnnotation(Swaps.class);
+ Swaps swaps = bc == null ? null : bc.getAnnotation(Swaps.class, innerClass);
if (swaps != null)
for (Swap s : swaps.value())
l.add(createPojoSwap(s));
@@ -727,7 +728,7 @@
}
if (ci.isChildOf(Surrogate.class)) {
- List<SurrogateSwap<?,?>> l = SurrogateSwap.findPojoSwaps(c);
+ List<SurrogateSwap<?,?>> l = SurrogateSwap.findPojoSwaps(c, beanContext);
if (! l.isEmpty())
return (PojoSwap<T,?>)l.iterator().next();
}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index 6ad4d2b..8877b6d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -316,10 +316,9 @@
throws IOException, ParseException, XMLStreamException {
String href = r.getAttributeValue(null, "href");
String name = getElementText(r);
- Class<T> beanClass = beanType.getInnerClass();
- if (beanClass.isAnnotationPresent(HtmlLink.class)) {
- HtmlLink h = beanClass.getAnnotation(HtmlLink.class);
- BeanMap<T> m = newBeanMap(beanClass);
+ if (beanType.hasAnnotation(HtmlLink.class)) {
+ HtmlLink h = beanType.getAnnotation(HtmlLink.class);
+ BeanMap<T> m = newBeanMap(beanType.getInnerClass());
m.put(h.uriProperty(), href);
m.put(h.nameProperty(), name);
return m.getBean();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index fff755e..9a5ac72 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -345,9 +345,8 @@
} else if (sType.isBean()) {
BeanMap m = toBeanMap(o);
- Class<?> c = o.getClass();
- if (c.isAnnotationPresent(HtmlLink.class)) {
- HtmlLink h = o.getClass().getAnnotation(HtmlLink.class);
+ if (aType.hasAnnotation(HtmlLink.class)) {
+ HtmlLink h = aType.getAnnotation(HtmlLink.class);
Object urlProp = m.get(h.uriProperty());
Object nameProp = m.get(h.nameProperty());
out.oTag("a").attrUri("href", urlProp).append('>').text(nameProp).eTag("a");
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
index c4426ee..8e9daad 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
@@ -95,9 +95,8 @@
}
Builder apply(Class<?> c) {
- ClassInfo ci = ClassInfo.of(c);
- apply(ci.getAnnotation(Request.class));
this.cm = BeanContext.DEFAULT.getClassMeta(c);
+ apply(cm.getAnnotation(Request.class));
for (MethodInfo m : cm.getInfo().getAllMethods()) {
if (m.isPublic()) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
index f365f01..f7008a9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
@@ -41,7 +41,7 @@
this.schema = new ObjectMap();
try {
- for (Schema s : bpm.getAnnotations(Schema.class, mp))
+ for (Schema s : bpm.getAnnotations(Schema.class))
schema.appendAll(SchemaUtils.asMap(s));
} catch (ParseException e) {
throw new RuntimeException(e);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
index 53290f6..f7a1ca1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/SurrogateSwap.java
@@ -53,14 +53,15 @@
* Returns an empty list if no public 1-arg constructors are found.
*
* @param c The surrogate class.
+ * @param bc The bean context to use for looking up annotations.
* @return The list of POJO swaps that apply to this class.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
- public static List<SurrogateSwap<?,?>> findPojoSwaps(Class<?> c) {
+ public static List<SurrogateSwap<?,?>> findPojoSwaps(Class<?> c, BeanContext bc) {
List<SurrogateSwap<?,?>> l = new LinkedList<>();
ClassInfo ci = ClassInfo.of(c);
for (ConstructorInfo cc : ci.getPublicConstructors()) {
- if (cc.getAnnotation(BeanIgnore.class) == null && cc.hasNumParams(1) && cc.isPublic()) {
+ if (! bc.hasAnnotation(BeanIgnore.class, cc) && cc.hasNumParams(1) && cc.isPublic()) {
Class<?> pt = cc.getRawParamType(0);
if (! pt.equals(c.getDeclaringClass())) {
// Find the unswap method if there is one.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/TwoKeyConcurrentHashMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/TwoKeyConcurrentHashMap.java
new file mode 100644
index 0000000..6a4829a
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/TwoKeyConcurrentHashMap.java
@@ -0,0 +1,75 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *
+// * with the License. You may obtain a copy of the License at *
+// * *
+// * http://www.apache.org/licenses/LICENSE-2.0 *
+// * *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *
+// * specific language governing permissions and limitations under the License. *
+// ***************************************************************************************************************************
+package org.apache.juneau.utils;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * A hashmap that allows for two-part keys.
+ * @param <K1> Key part 1 type.
+ * @param <K2> Key part 2 type.
+ * @param <V> Value type.
+ */
+public class TwoKeyConcurrentHashMap<K1,K2,V> extends ConcurrentHashMap<TwoKeyConcurrentHashMap.Key<K1,K2>,V> {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Adds an entry to this map.
+ *
+ * @param key1 Key part 1. Can be <jk>null</jk>.
+ * @param key2 Key part 2. Can be <jk>null</jk>.
+ * @param value Value.
+ * @return The previous value if there was one.
+ */
+ public V put(K1 key1, K2 key2, V value) {
+ Key<K1,K2> key = new Key<>(key1, key2);
+ return super.put(key, value);
+ }
+
+ /**
+ * Retrieves an entry from this map.
+ *
+ * @param key1 Key part 1. Can be <jk>null</jk>.
+ * @param key2 Key part 2. Can be <jk>null</jk>.
+ * @return The previous value if there was one.
+ */
+ public V get(K1 key1, K2 key2) {
+ Key<K1,K2> key = new Key<>(key1, key2);
+ return super.get(key);
+ }
+
+ static class Key<K1,K2> {
+ final K1 k1;
+ final K2 k2;
+ final int hashCode;
+
+ Key(K1 k1, K2 k2) {
+ this.k1 = k1;
+ this.k2 = k2;
+ this.hashCode = 31*(k1 == null ? 0 : k1.hashCode()) + (k2 == null ? 0 : k2.hashCode());
+ }
+
+ @Override /* Object */
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override /* Object */
+ @SuppressWarnings("unchecked")
+ public boolean equals(Object o) {
+ Key<K1,K2> ko = (Key<K1,K2>)o;
+ return Objects.equals(k1, ko.k1) && Objects.equals(k2, ko.k2);
+ }
+ }
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
index 6687e96..66a1740 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
@@ -43,7 +43,7 @@
super(bpm);
this.xmlMetaProvider = mp;
- for (Xml xml : bpm.getAnnotations(Xml.class, mp))
+ for (Xml xml : bpm.getAnnotations(Xml.class))
findXmlInfo(xml, mp);
if (namespace == null)
@@ -104,8 +104,8 @@
ClassMeta<?> cmBean = bpm.getBeanMeta().getClassMeta();
String name = bpm.getName();
- List<Xml> xmls = bpm.getAllAnnotations(Xml.class, mp);
- List<XmlSchema> schemas = bpm.getAllAnnotations(XmlSchema.class, mp);
+ List<Xml> xmls = bpm.getAllAnnotations(Xml.class);
+ List<XmlSchema> schemas = bpm.getAllAnnotations(XmlSchema.class);
namespace = XmlUtils.findNamespace(xmls, schemas);
if (xmlFormat == XmlFormat.DEFAULT)