Skip to content

Commit e585a8f

Browse files
committed
Merge pull request #521 from tea-dragon/master
keep bundle annotations and prevent simple cycles
2 parents d1f58c6 + 21df384 commit e585a8f

File tree

4 files changed

+78
-21
lines changed

4 files changed

+78
-21
lines changed

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedClass.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -908,13 +908,13 @@ private void _addAnnotationsIfNotPresent(AnnotationMap result, Annotation[] anns
908908
if (anns != null) {
909909
List<Annotation[]> bundles = null;
910910
for (Annotation ann : anns) { // first: direct annotations
911-
if (_isAnnotationBundle(ann)) {
911+
// note: we will NOT filter out non-Jackson anns any more
912+
boolean wasNotPresent = result.addIfNotPresent(ann);
913+
if (wasNotPresent && _isAnnotationBundle(ann)) {
912914
if (bundles == null) {
913915
bundles = new LinkedList<Annotation[]>();
914916
}
915917
bundles.add(ann.annotationType().getDeclaredAnnotations());
916-
} else { // note: we will NOT filter out non-Jackson anns any more
917-
result.addIfNotPresent(ann);
918918
}
919919
}
920920
if (bundles != null) { // and secondarily handle bundles, if any found: precedence important
@@ -930,13 +930,13 @@ private void _addAnnotationsIfNotPresent(AnnotatedMember target, Annotation[] an
930930
if (anns != null) {
931931
List<Annotation[]> bundles = null;
932932
for (Annotation ann : anns) { // first: direct annotations
933-
if (_isAnnotationBundle(ann)) {
933+
// note: we will NOT filter out non-Jackson anns any more
934+
boolean wasNotPresent = target.addIfNotPresent(ann);
935+
if (wasNotPresent && _isAnnotationBundle(ann)) {
934936
if (bundles == null) {
935937
bundles = new LinkedList<Annotation[]>();
936938
}
937939
bundles.add(ann.annotationType().getDeclaredAnnotations());
938-
} else { // note: we will NOT filter out non-Jackson anns any more
939-
target.addIfNotPresent(ann);
940940
}
941941
}
942942
if (bundles != null) { // and secondarily handle bundles, if any found: precedence important
@@ -952,13 +952,13 @@ private void _addOrOverrideAnnotations(AnnotatedMember target, Annotation[] anns
952952
if (anns != null) {
953953
List<Annotation[]> bundles = null;
954954
for (Annotation ann : anns) { // first: direct annotations
955-
if (_isAnnotationBundle(ann)) {
955+
// note: we will NOT filter out non-Jackson anns any more
956+
boolean wasModified = target.addOrOverride(ann);
957+
if (wasModified && _isAnnotationBundle(ann)) {
956958
if (bundles == null) {
957959
bundles = new LinkedList<Annotation[]>();
958960
}
959961
bundles.add(ann.annotationType().getDeclaredAnnotations());
960-
} else { // note: no filtering by jackson-annotations
961-
target.addOrOverride(ann);
962962
}
963963
}
964964
if (bundles != null) { // and then bundles, if any: important for precedence

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotatedMember.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,17 @@ protected AnnotationMap getAllAnnotations() {
5151
* annotation masking or overriding an annotation 'real' constructor
5252
* has.
5353
*/
54-
public final void addOrOverride(Annotation a) {
55-
_annotations.add(a);
54+
public final boolean addOrOverride(Annotation a) {
55+
return _annotations.add(a);
5656
}
5757

5858
/**
5959
* Method called to augment annotations, by adding specified
6060
* annotation if and only if it is not yet present in the
6161
* annotation map we have.
6262
*/
63-
public final void addIfNotPresent(Annotation a) {
64-
_annotations.addIfNotPresent(a);
63+
public final boolean addIfNotPresent(Annotation a) {
64+
return _annotations.addIfNotPresent(a);
6565
}
6666

6767
/**

src/main/java/com/fasterxml/jackson/databind/introspect/AnnotationMap.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,20 @@ public int size() {
7171
* Method called to add specified annotation in the Map, but
7272
* only if it didn't yet exist.
7373
*/
74-
public void addIfNotPresent(Annotation ann)
74+
public boolean addIfNotPresent(Annotation ann)
7575
{
7676
if (_annotations == null || !_annotations.containsKey(ann.annotationType())) {
7777
_add(ann);
78+
return true;
7879
}
80+
return false;
7981
}
8082

8183
/**
8284
* Method called to add specified annotation in the Map.
8385
*/
84-
public void add(Annotation ann) {
85-
_add(ann);
86+
public boolean add(Annotation ann) {
87+
return _add(ann);
8688
}
8789

8890
@Override
@@ -99,11 +101,12 @@ public String toString() {
99101
/**********************************************************
100102
*/
101103

102-
protected final void _add(Annotation ann) {
104+
protected final boolean _add(Annotation ann) {
103105
if (_annotations == null) {
104106
_annotations = new HashMap<Class<? extends Annotation>,Annotation>();
105107
}
106-
_annotations.put(ann.annotationType(), ann);
108+
Annotation previous = _annotations.put(ann.annotationType(), ann);
109+
return (previous != null) && previous.equals(ann);
107110
}
108111
}
109112

src/test/java/com/fasterxml/jackson/databind/introspect/TestAnnotionBundles.java

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
import java.lang.annotation.Retention;
44
import java.lang.annotation.RetentionPolicy;
55

6-
import com.fasterxml.jackson.annotation.*;
6+
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
7+
import com.fasterxml.jackson.annotation.JsonAutoDetect;
78
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
9+
import com.fasterxml.jackson.annotation.JsonIgnore;
10+
import com.fasterxml.jackson.annotation.JsonProperty;
811
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import com.fasterxml.jackson.databind.PropertyName;
913

1014
/* Tests mostly for [JACKSON-754]: ability to create "annotation bundles"
1115
*/
@@ -51,15 +55,65 @@ public class NoAutoDetect {
5155
public class Bean92 {
5256
@Bundle92
5357
protected String id = "abc";
54-
}
58+
}
59+
60+
@HolderB
61+
@JacksonAnnotationsInside
62+
@Retention(RetentionPolicy.RUNTIME)
63+
static @interface HolderA {}
64+
65+
@HolderA
66+
@JacksonAnnotationsInside
67+
@Retention(RetentionPolicy.RUNTIME)
68+
static @interface HolderB {}
69+
70+
static class RecursiveHolder {
71+
@HolderA public int unimportant = 42;
72+
}
73+
74+
@JsonProperty
75+
@JacksonAnnotationsInside
76+
@Retention(RetentionPolicy.RUNTIME)
77+
static @interface InformativeHolder {
78+
// doesn't really contribute to the test, but would be impossible without this feature
79+
boolean important() default true;
80+
}
81+
82+
static class InformingHolder {
83+
@InformativeHolder public int unimportant = 42;
84+
}
85+
86+
static class BundleAnnotationIntrospector extends JacksonAnnotationIntrospector {
87+
@Override
88+
public PropertyName findNameForSerialization(Annotated a)
89+
{
90+
InformativeHolder informativeHolder = a.getAnnotation(InformativeHolder.class);
91+
if ((informativeHolder != null) && informativeHolder.important()) {
92+
return new PropertyName("important");
93+
}
94+
return super.findNameForSerialization(a);
95+
}
96+
}
97+
5598
/*
5699
/**********************************************************
57100
/* Test methods
58101
/**********************************************************
59102
*/
60103

61104
private final ObjectMapper MAPPER = new ObjectMapper();
62-
105+
106+
public void testKeepAnnotationBundle() throws Exception
107+
{
108+
MAPPER.setAnnotationIntrospector(new BundleAnnotationIntrospector());
109+
assertEquals("{\"important\":42}", MAPPER.writeValueAsString(new InformingHolder()));
110+
}
111+
112+
public void testRecursiveBundles() throws Exception
113+
{
114+
assertEquals("{\"unimportant\":42}", MAPPER.writeValueAsString(new RecursiveHolder()));
115+
}
116+
63117
public void testBundledIgnore() throws Exception
64118
{
65119
assertEquals("{\"foobar\":13}", MAPPER.writeValueAsString(new Bean()));

0 commit comments

Comments
 (0)