From 6dcb13f70fb1c68b0c055bfb1dae2b296ae67b03 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Sun, 26 Apr 2015 22:24:57 -0700 Subject: [PATCH] Streamlining `AnnotatedClass` slightly, trying to figure out #771 --- .../databind/introspect/AnnotatedClass.java | 73 +++++++++---------- .../mixins/MixinsWithBundlesTest.java | 43 +++++++++++ 2 files changed, 79 insertions(+), 37 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/databind/mixins/MixinsWithBundlesTest.java diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java index fb2bfd6283..2224bae565 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java @@ -1,6 +1,8 @@ package com.fasterxml.jackson.databind.introspect; import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; import java.lang.reflect.*; import java.util.*; @@ -894,55 +896,58 @@ protected AnnotationMap[] _collectRelevantAnnotations(Annotation[][] anns) protected AnnotationMap _collectRelevantAnnotations(Annotation[] anns) { - AnnotationMap annMap = new AnnotationMap(); - _addAnnotationsIfNotPresent(annMap, anns); - return annMap; + return _addAnnotationsIfNotPresent(new AnnotationMap(), anns); } /* Helper method used to add all applicable annotations from given set. * Takes into account possible "annotation bundles" (meta-annotations to * include instead of main-level annotation) */ - private void _addAnnotationsIfNotPresent(AnnotationMap result, Annotation[] anns) + private AnnotationMap _addAnnotationsIfNotPresent(AnnotationMap result, Annotation[] anns) { if (anns != null) { - List bundles = null; + List fromBundles = null; for (Annotation ann : anns) { // first: direct annotations // note: we will NOT filter out non-Jackson anns any more boolean wasNotPresent = result.addIfNotPresent(ann); if (wasNotPresent && _isAnnotationBundle(ann)) { - if (bundles == null) { - bundles = new LinkedList(); - } - bundles.add(ann.annotationType().getDeclaredAnnotations()); + fromBundles = _addFromBundle(ann, fromBundles); } } - if (bundles != null) { // and secondarily handle bundles, if any found: precedence important - for (Annotation[] annotations : bundles) { - _addAnnotationsIfNotPresent(result, annotations); - } + if (fromBundles != null) { // and secondarily handle bundles, if any found: precedence important + _addAnnotationsIfNotPresent(result, fromBundles.toArray(new Annotation[fromBundles.size()])); } } + return result; } + private List _addFromBundle(Annotation bundle, List result) + { + for (Annotation a : bundle.annotationType().getDeclaredAnnotations()) { + // minor optimization: by-pass 2 common JDK meta-annotations + if ((a instanceof Target) || (a instanceof Retention)) { + continue; + } + if (result == null) { + result = new ArrayList(); + } + result.add(a); + } + return result; + } + private void _addAnnotationsIfNotPresent(AnnotatedMember target, Annotation[] anns) { if (anns != null) { - List bundles = null; + List fromBundles = null; for (Annotation ann : anns) { // first: direct annotations - // note: we will NOT filter out non-Jackson anns any more boolean wasNotPresent = target.addIfNotPresent(ann); if (wasNotPresent && _isAnnotationBundle(ann)) { - if (bundles == null) { - bundles = new LinkedList(); - } - bundles.add(ann.annotationType().getDeclaredAnnotations()); + fromBundles = _addFromBundle(ann, fromBundles); } } - if (bundles != null) { // and secondarily handle bundles, if any found: precedence important - for (Annotation[] annotations : bundles) { - _addAnnotationsIfNotPresent(target, annotations); - } + if (fromBundles != null) { // and secondarily handle bundles, if any found: precedence important + _addAnnotationsIfNotPresent(target, fromBundles.toArray(new Annotation[fromBundles.size()])); } } } @@ -950,21 +955,15 @@ private void _addAnnotationsIfNotPresent(AnnotatedMember target, Annotation[] an private void _addOrOverrideAnnotations(AnnotatedMember target, Annotation[] anns) { if (anns != null) { - List bundles = null; + List fromBundles = null; for (Annotation ann : anns) { // first: direct annotations - // note: we will NOT filter out non-Jackson anns any more boolean wasModified = target.addOrOverride(ann); if (wasModified && _isAnnotationBundle(ann)) { - if (bundles == null) { - bundles = new LinkedList(); - } - bundles.add(ann.annotationType().getDeclaredAnnotations()); + fromBundles = _addFromBundle(ann, fromBundles); } } - if (bundles != null) { // and then bundles, if any: important for precedence - for (Annotation[] annotations : bundles) { - _addOrOverrideAnnotations(target, annotations); - } + if (fromBundles != null) { // and then bundles, if any: important for precedence + _addOrOverrideAnnotations(target, fromBundles.toArray(new Annotation[fromBundles.size()])); } } } @@ -1013,10 +1012,10 @@ protected void _addMixUnders(Method src, AnnotatedMethod target) { _addAnnotationsIfNotPresent(target, src.getDeclaredAnnotations()); } - private final boolean _isAnnotationBundle(Annotation ann) { - return (_annotationIntrospector != null) && _annotationIntrospector.isAnnotationBundle(ann); - } - + private final boolean _isAnnotationBundle(Annotation ann) { + return (_annotationIntrospector != null) && _annotationIntrospector.isAnnotationBundle(ann); + } + /* /********************************************************** /* Other methods diff --git a/src/test/java/com/fasterxml/jackson/databind/mixins/MixinsWithBundlesTest.java b/src/test/java/com/fasterxml/jackson/databind/mixins/MixinsWithBundlesTest.java new file mode 100644 index 0000000000..79dc4947e7 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/mixins/MixinsWithBundlesTest.java @@ -0,0 +1,43 @@ +package com.fasterxml.jackson.databind.mixins; + +import java.lang.annotation.*; + +import com.fasterxml.jackson.annotation.*; + +import com.fasterxml.jackson.databind.*; + +// for [databind#771] +public class MixinsWithBundlesTest extends BaseMapTest +{ + @Target(value={ ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD }) + @Retention(value=RetentionPolicy.RUNTIME) + @JacksonAnnotationsInside + @JsonProperty("bar") + public @interface ExposeStuff { + + } + + public abstract class FooMixin { + @ExposeStuff + public abstract String getStuff(); + } + + public static class Foo { + + private String stuff; + + Foo(String stuff) { + this.stuff = stuff; + } + + public String getStuff() { + return stuff; + } + } + public void testMixinWithBundles() throws Exception + { + ObjectMapper mapper = new ObjectMapper().addMixIn(Foo.class, FooMixin.class); + String result = mapper.writeValueAsString(new Foo("result")); + assertEquals("{\"bar\":\"result\"}", result); + } +}