1 package com.fasterxml.jackson.databind.introspect;
2 
3 import java.util.HashMap;
4 import java.util.Map;
5 
6 import com.fasterxml.jackson.databind.type.ClassKey;
7 
8 /**
9  * Simple implementation of {@link ClassIntrospector.MixInResolver}
10  * that just uses a {@link java.util.Map} for containing mapping
11  * from target to mix-in classes.
12  *<p>
13  * Implementation is only thread-safe after initialization (that is,
14  * when underlying Map is not modified but only read).
15  *
16  * @since 2.6
17  */
18 public class SimpleMixInResolver
19     implements ClassIntrospector.MixInResolver,
20         java.io.Serializable
21 {
22     private static final long serialVersionUID = 1L;
23 
24     /**
25      * External resolver that gets called before looking at any locally defined
26      * mix-in target classes.
27      */
28     protected final ClassIntrospector.MixInResolver _overrides;
29 
30     /**
31      * Simple mix-in targets defined locally.
32      */
33     protected Map<ClassKey,Class<?>> _localMixIns;
34 
SimpleMixInResolver(ClassIntrospector.MixInResolver overrides)35     public SimpleMixInResolver(ClassIntrospector.MixInResolver overrides) {
36         _overrides = overrides;
37     }
38 
SimpleMixInResolver(ClassIntrospector.MixInResolver overrides, Map<ClassKey,Class<?>> mixins)39     protected SimpleMixInResolver(ClassIntrospector.MixInResolver overrides,
40             Map<ClassKey,Class<?>> mixins) {
41         _overrides = overrides;
42         _localMixIns = mixins;
43     }
44 
45     /**
46      * Mutant factory for constructor a new resolver instance with given
47      * mix-in resolver override.
48      */
withOverrides(ClassIntrospector.MixInResolver overrides)49     public SimpleMixInResolver withOverrides(ClassIntrospector.MixInResolver overrides) {
50         return new SimpleMixInResolver(overrides, _localMixIns);
51     }
52 
53     /**
54      * Mutant factory method that constructs a new instance that has no locally
55      * defined mix-in/target mappings.
56      */
withoutLocalDefinitions()57     public SimpleMixInResolver withoutLocalDefinitions() {
58         return new SimpleMixInResolver(_overrides, null);
59     }
60 
setLocalDefinitions(Map<Class<?>, Class<?>> sourceMixins)61     public void setLocalDefinitions(Map<Class<?>, Class<?>> sourceMixins) {
62         if (sourceMixins == null || sourceMixins.isEmpty()) {
63             _localMixIns = null;
64         } else {
65             Map<ClassKey,Class<?>> mixIns = new HashMap<ClassKey,Class<?>>(sourceMixins.size());
66             for (Map.Entry<Class<?>,Class<?>> en : sourceMixins.entrySet()) {
67                 mixIns.put(new ClassKey(en.getKey()), en.getValue());
68             }
69             _localMixIns = mixIns;
70         }
71     }
72 
addLocalDefinition(Class<?> target, Class<?> mixinSource)73     public void addLocalDefinition(Class<?> target, Class<?> mixinSource) {
74         if (_localMixIns == null) {
75             _localMixIns = new HashMap<ClassKey,Class<?>>();
76         }
77         _localMixIns.put(new ClassKey(target), mixinSource);
78     }
79 
80     @Override
copy()81     public SimpleMixInResolver copy() {
82         ClassIntrospector.MixInResolver overrides = (_overrides == null)
83                 ? null : _overrides.copy();
84         Map<ClassKey,Class<?>> mixIns = (_localMixIns == null)
85                 ? null : new HashMap<ClassKey,Class<?>>(_localMixIns);
86         return new SimpleMixInResolver(overrides, mixIns);
87     }
88 
89     @Override
findMixInClassFor(Class<?> cls)90     public Class<?> findMixInClassFor(Class<?> cls)
91     {
92         Class<?> mixin = (_overrides == null) ? null : _overrides.findMixInClassFor(cls);
93         if (mixin == null && (_localMixIns != null)) {
94             mixin = _localMixIns.get(new ClassKey(cls));
95         }
96         return mixin;
97     }
98 
localSize()99     public int localSize() {
100         return (_localMixIns == null) ? 0 : _localMixIns.size();
101     }
102 
103     /**
104      * Method that may be called for optimization purposes, to see if calls to
105      * mix-in resolver may be avoided. Return value of {@code true} means that
106      * it is possible that a mix-in class will be found; {@code false} that no
107      * mix-in will ever be found. In latter case caller can avoid calls altogether.
108      *<p>
109      * Note that the reason for "empty" resolvers is to use "null object" for simplifying
110      * code.
111      *
112      * @return True, if this resolver MAY have mix-ins to apply; false if not (it
113      *   is "empty")
114      *
115      * @since 2.10.1
116      */
hasMixIns()117     public boolean hasMixIns() {
118         if (_localMixIns == null) {
119             // if neither local mix-ins nor overrides, no mix-ins
120             if (_overrides == null) {
121                 return false;
122             }
123             // or, if no local mix-ins and can delegate to resolver
124             if (_overrides instanceof SimpleMixInResolver) {
125                 return ((SimpleMixInResolver) _overrides).hasMixIns();
126             }
127         }
128         // cannot rule out the possibility, so...
129         return true;
130     }
131 }
132