1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.lang.annotation.Annotation;
4 import java.util.*;
5
6 import com.fasterxml.jackson.databind.util.Annotations;
7
8 /**
9  * Simple helper class used to keep track of collection of
10  * Jackson Annotations associated with annotatable things
11  * (methods, constructors, classes).
12  * Note that only Jackson-owned annotations are tracked (for now?).
13  */

14 public final class AnnotationMap implements Annotations
15 {
16     protected HashMap<Class<?>,Annotation> _annotations;
17
18     public AnnotationMap() { }
19
20     public static AnnotationMap of(Class<?> type, Annotation value) {
21         HashMap<Class<?>,Annotation> ann = new HashMap<>(4);
22         ann.put(type, value);
23         return new AnnotationMap(ann);
24     }
25
26     AnnotationMap(HashMap<Class<?>,Annotation> a) {
27         _annotations = a;
28     }
29
30     /*
31     /**********************************************************
32     /* Annotations impl
33     /**********************************************************
34      */

35     
36     @SuppressWarnings("unchecked")
37     @Override
38     public <A extends Annotation> A get(Class<A> cls)
39     {
40         if (_annotations == null) {
41             return null;
42         }
43         return (A) _annotations.get(cls);
44     }
45
46     @Override
47     public boolean has(Class<?> cls)
48     {
49         if (_annotations == null) {
50             return false;
51         }
52         return _annotations.containsKey(cls);
53     }
54
55     /**
56      * Helper method that can be used for a "bulk" check to see if at least
57      * one of given annotation types is included within this map.
58      *
59      * @since 2.7
60      */

61     @Override
62     public boolean hasOneOf(Class<? extends Annotation>[] annoClasses) {
63         if (_annotations != null) {
64             for (int i = 0, end = annoClasses.length; i < end; ++i) {
65                 if (_annotations.containsKey(annoClasses[i])) {
66                     return true;
67                 }
68             }
69         }
70         return false;
71     }
72
73     /*
74     /**********************************************************
75     /* Other API
76     /**********************************************************
77      */

78     
79     /**
80      * @since 2.3
81      */

82     public Iterable<Annotation> annotations() {
83         if (_annotations == null || _annotations.size() == 0) {
84             return Collections.emptyList();
85         }
86         return _annotations.values();
87     }
88     
89     public static AnnotationMap merge(AnnotationMap primary, AnnotationMap secondary)
90     {
91         if (primary == null || primary._annotations == null || primary._annotations.isEmpty()) {
92             return secondary;
93         }
94         if (secondary == null || secondary._annotations == null || secondary._annotations.isEmpty()) {
95             return primary;
96         }
97         HashMap<Class<?>,Annotation> annotations = new HashMap<Class<?>,Annotation>();
98         // add secondary ones first
99         for (Annotation ann : secondary._annotations.values()) {
100             annotations.put(ann.annotationType(), ann);
101         }
102         // to be overridden by primary ones
103         for (Annotation ann : primary._annotations.values()) {
104             annotations.put(ann.annotationType(), ann);
105         }
106         return new AnnotationMap(annotations);
107     }
108     
109     @Override
110     public int size() {
111         return (_annotations == null) ? 0 : _annotations.size();
112     }
113
114     /**
115      * Method called to add specified annotation in the Map, but
116      * only if it didn't yet exist.
117      */

118     public boolean addIfNotPresent(Annotation ann)
119     {
120         if (_annotations == null || !_annotations.containsKey(ann.annotationType())) {
121             _add(ann);
122             return true;
123         }
124         return false;
125     }
126
127     /**
128      * Method called to add specified annotation in the Map.
129      * 
130      * @return True if the addition changed the contents, that is, this map did not
131      *   already have specified annotation
132      */

133     public boolean add(Annotation ann) {
134         return _add(ann);
135     }
136
137     @Override
138     public String toString() {
139         if (_annotations == null) {
140             return "[null]";
141         }
142         return _annotations.toString();
143     }
144
145     /*
146     /**********************************************************
147     /* Helper methods
148     /**********************************************************
149      */

150
151     protected final boolean _add(Annotation ann) {
152         if (_annotations == null) {
153             _annotations = new HashMap<Class<?>,Annotation>();
154         }
155         Annotation previous = _annotations.put(ann.annotationType(), ann);
156         return (previous == null) || !previous.equals(ann);
157     }
158 }
159