| package com.fasterxml.jackson.databind.introspect; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import com.fasterxml.jackson.databind.type.ClassKey; |
| |
| /** |
| * Simple implementation of {@link ClassIntrospector.MixInResolver} |
| * that just uses a {@link java.util.Map} for containing mapping |
| * from target to mix-in classes. |
| *<p> |
| * Implementation is only thread-safe after initialization (that is, |
| * when underlying Map is not modified but only read). |
| * |
| * @since 2.6 |
| */ |
| public class SimpleMixInResolver |
| implements ClassIntrospector.MixInResolver, |
| java.io.Serializable |
| { |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * External resolver that gets called before looking at any locally defined |
| * mix-in target classes. |
| */ |
| protected final ClassIntrospector.MixInResolver _overrides; |
| |
| /** |
| * Simple mix-in targets defined locally. |
| */ |
| protected Map<ClassKey,Class<?>> _localMixIns; |
| |
| public SimpleMixInResolver(ClassIntrospector.MixInResolver overrides) { |
| _overrides = overrides; |
| } |
| |
| protected SimpleMixInResolver(ClassIntrospector.MixInResolver overrides, |
| Map<ClassKey,Class<?>> mixins) { |
| _overrides = overrides; |
| _localMixIns = mixins; |
| } |
| |
| /** |
| * Mutant factory for constructor a new resolver instance with given |
| * mix-in resolver override. |
| */ |
| public SimpleMixInResolver withOverrides(ClassIntrospector.MixInResolver overrides) { |
| return new SimpleMixInResolver(overrides, _localMixIns); |
| } |
| |
| /** |
| * Mutant factory method that constructs a new instance that has no locally |
| * defined mix-in/target mappings. |
| */ |
| public SimpleMixInResolver withoutLocalDefinitions() { |
| return new SimpleMixInResolver(_overrides, null); |
| } |
| |
| public void setLocalDefinitions(Map<Class<?>, Class<?>> sourceMixins) { |
| if (sourceMixins == null || sourceMixins.isEmpty()) { |
| _localMixIns = null; |
| } else { |
| Map<ClassKey,Class<?>> mixIns = new HashMap<ClassKey,Class<?>>(sourceMixins.size()); |
| for (Map.Entry<Class<?>,Class<?>> en : sourceMixins.entrySet()) { |
| mixIns.put(new ClassKey(en.getKey()), en.getValue()); |
| } |
| _localMixIns = mixIns; |
| } |
| } |
| |
| public void addLocalDefinition(Class<?> target, Class<?> mixinSource) { |
| if (_localMixIns == null) { |
| _localMixIns = new HashMap<ClassKey,Class<?>>(); |
| } |
| _localMixIns.put(new ClassKey(target), mixinSource); |
| } |
| |
| @Override |
| public SimpleMixInResolver copy() { |
| ClassIntrospector.MixInResolver overrides = (_overrides == null) |
| ? null : _overrides.copy(); |
| Map<ClassKey,Class<?>> mixIns = (_localMixIns == null) |
| ? null : new HashMap<ClassKey,Class<?>>(_localMixIns); |
| return new SimpleMixInResolver(overrides, mixIns); |
| } |
| |
| @Override |
| public Class<?> findMixInClassFor(Class<?> cls) |
| { |
| Class<?> mixin = (_overrides == null) ? null : _overrides.findMixInClassFor(cls); |
| if (mixin == null && (_localMixIns != null)) { |
| mixin = _localMixIns.get(new ClassKey(cls)); |
| } |
| return mixin; |
| } |
| |
| public int localSize() { |
| return (_localMixIns == null) ? 0 : _localMixIns.size(); |
| } |
| |
| /** |
| * Method that may be called for optimization purposes, to see if calls to |
| * mix-in resolver may be avoided. Return value of {@code true} means that |
| * it is possible that a mix-in class will be found; {@code false} that no |
| * mix-in will ever be found. In latter case caller can avoid calls altogether. |
| *<p> |
| * Note that the reason for "empty" resolvers is to use "null object" for simplifying |
| * code. |
| * |
| * @return True, if this resolver MAY have mix-ins to apply; false if not (it |
| * is "empty") |
| * |
| * @since 2.10.1 |
| */ |
| public boolean hasMixIns() { |
| if (_localMixIns == null) { |
| // if neither local mix-ins nor overrides, no mix-ins |
| if (_overrides == null) { |
| return false; |
| } |
| // or, if no local mix-ins and can delegate to resolver |
| if (_overrides instanceof SimpleMixInResolver) { |
| return ((SimpleMixInResolver) _overrides).hasMixIns(); |
| } |
| } |
| // cannot rule out the possibility, so... |
| return true; |
| } |
| } |