1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.annotation.Annotation;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.Map;
7
8 import com.fasterxml.jackson.databind.util.Annotations;
9
10 /**
11  * Helper class used to collect annotations to be stored as
12  * {@link com.fasterxml.jackson.databind.util.Annotations} (like {@link AnnotationMap}).
13  *
14  * @since 2.9
15  */

16 public abstract class AnnotationCollector
17 {
18     protected final static Annotations NO_ANNOTATIONS = new NoAnnotations();
19
20     /**
21      * Optional data to carry along
22      */

23     protected final Object _data;
24
25     protected AnnotationCollector(Object d) {
26         _data = d;
27     }
28
29     public static Annotations emptyAnnotations() { return NO_ANNOTATIONS; }
30
31     public static AnnotationCollector emptyCollector() {
32         return EmptyCollector.instance;
33     }
34
35     public static AnnotationCollector emptyCollector(Object data) {
36         return new EmptyCollector(data);
37     }
38
39     public abstract Annotations asAnnotations();
40     public abstract AnnotationMap asAnnotationMap();
41
42     public Object getData() {
43         return _data;
44     }
45
46     /*
47     /**********************************************************
48     /* API
49     /**********************************************************
50      */

51
52     public abstract boolean isPresent(Annotation ann);
53
54     public abstract AnnotationCollector addOrOverride(Annotation ann);
55
56     /*
57     /**********************************************************
58     /* Collector implementations
59     /**********************************************************
60      */

61
62     static class EmptyCollector extends AnnotationCollector
63     {
64         public final static EmptyCollector instance = new EmptyCollector(null);
65
66         EmptyCollector(Object data) { super(data); }
67
68         @Override
69         public Annotations asAnnotations() {
70             return NO_ANNOTATIONS;
71         }
72  
73         @Override
74         public AnnotationMap asAnnotationMap() {
75             return new AnnotationMap();
76         }
77
78         @Override
79         public boolean isPresent(Annotation ann) { return false; }
80
81         @Override
82         public AnnotationCollector addOrOverride(Annotation ann) {
83             return new OneCollector(_data, ann.annotationType(), ann);
84         }
85     }
86
87     static class OneCollector extends AnnotationCollector
88     {
89         private Class<?> _type;
90         private Annotation _value;
91
92         public OneCollector(Object data,
93                 Class<?> type, Annotation value) {
94             super(data);
95             _type = type;
96             _value = value;
97         }
98
99         @Override
100         public Annotations asAnnotations() {
101             return new OneAnnotation(_type, _value);
102         }
103
104         @Override
105         public AnnotationMap asAnnotationMap() {
106             return AnnotationMap.of(_type, _value);
107         }
108
109         @Override
110         public boolean isPresent(Annotation ann) {
111             return ann.annotationType() == _type;
112         }
113         
114         @Override
115         public AnnotationCollector addOrOverride(Annotation ann) {
116             final Class<?> type = ann.annotationType();
117             // true override? Just replace in-place, return
118             if (_type == type) {
119                 _value = ann;
120                 return this;
121             }
122             return new NCollector(_data, _type, _value, type, ann);
123         }
124     }
125
126     static class NCollector extends AnnotationCollector
127     {
128         protected final HashMap<Class<?>,Annotation> _annotations;
129
130         public NCollector(Object data,
131                 Class<?> type1, Annotation value1,
132                 Class<?> type2, Annotation value2) {
133             super(data);
134             _annotations = new HashMap<>();
135             _annotations.put(type1, value1);
136             _annotations.put(type2, value2);
137         }
138
139         @Override
140         public Annotations asAnnotations() {
141             if (_annotations.size() == 2) {
142                 Iterator<Map.Entry<Class<?>,Annotation>> it = _annotations.entrySet().iterator();
143                 Map.Entry<Class<?>,Annotation> en1 = it.next(), en2 = it.next();
144                 return new TwoAnnotations(en1.getKey(), en1.getValue(),
145                         en2.getKey(), en2.getValue());
146             }
147             return new AnnotationMap(_annotations);
148         }
149
150         @Override
151         public AnnotationMap asAnnotationMap() {
152             AnnotationMap result = new AnnotationMap();
153             for (Annotation ann : _annotations.values()) {
154                 result.add(ann);
155             }
156             return result;
157         }
158
159         @Override
160         public boolean isPresent(Annotation ann) {
161             return _annotations.containsKey(ann.annotationType());
162         }
163
164         @Override
165         public AnnotationCollector addOrOverride(Annotation ann) {
166             _annotations.put(ann.annotationType(), ann);
167             return this;
168         }
169     }
170
171     /*
172     /**********************************************************
173     /* Annotations implementations
174     /**********************************************************
175      */

176
177     /**
178      * Immutable implementation for case where no annotations are associated with
179      * an annotatable entity.
180      *
181      * @since 2.9
182      */

183     public static class NoAnnotations
184         implements Annotations, java.io.Serializable
185     {
186         private static final long serialVersionUID = 1L;
187
188         NoAnnotations() { }
189
190         @Override
191         public <A extends Annotation> A get(Class<A> cls) {
192             return null;
193         }
194
195         @Override
196         public boolean has(Class<?> cls) {
197             return false;
198         }
199
200         @Override
201         public boolean hasOneOf(Class<? extends Annotation>[] annoClasses) {
202             return false;
203         }
204
205         @Override
206         public int size() {
207             return 0;
208         }
209     }
210
211     public static class OneAnnotation
212         implements Annotations, java.io.Serializable
213     {
214         private static final long serialVersionUID = 1L;
215
216         private final Class<?> _type;
217         private final Annotation _value;
218
219         public OneAnnotation(Class<?> type, Annotation value) {
220             _type = type;
221             _value = value;
222         }
223
224         @SuppressWarnings("unchecked")
225         @Override
226         public <A extends Annotation> A get(Class<A> cls) {
227             if (_type == cls) {
228                 return (A) _value;
229             }
230             return null;
231         }
232
233         @Override
234         public boolean has(Class<?> cls) {
235             return (_type == cls);
236         }
237
238         @Override
239         public boolean hasOneOf(Class<? extends Annotation>[] annoClasses) {
240             for (Class<?> cls : annoClasses) {
241                 if (cls == _type) {
242                     return true;
243                 }
244             }
245             return false;
246         }
247
248         @Override
249         public int size() {
250             return 1;
251         }
252     }
253
254     public static class TwoAnnotations
255         implements Annotations, java.io.Serializable
256     {
257         private static final long serialVersionUID = 1L;
258     
259         private final Class<?> _type1, _type2;
260         private final Annotation _value1, _value2;
261     
262         public TwoAnnotations(Class<?> type1, Annotation value1,
263                 Class<?> type2, Annotation value2) {
264             _type1 = type1;
265             _value1 = value1;
266             _type2 = type2;
267             _value2 = value2;
268         }
269
270         @SuppressWarnings("unchecked")
271         @Override
272         public <A extends Annotation> A get(Class<A> cls) {
273             if (_type1 == cls) {
274                 return (A) _value1;
275             }
276             if (_type2 == cls) {
277                 return (A) _value2;
278             }
279             return null;
280         }
281
282         @Override
283         public boolean has(Class<?> cls) {
284             return (_type1 == cls) || (_type2 == cls);
285         }
286
287         @Override
288         public boolean hasOneOf(Class<? extends Annotation>[] annoClasses) {
289             for (Class<?> cls : annoClasses) {
290                 if ((cls == _type1) || (cls == _type2)) {
291                     return true;
292                 }
293             }
294             return false;
295         }
296
297         @Override
298         public int size() {
299             return 2;
300         }
301     }
302 }
303