1
2
3
4
5
6
7
8
9
10
11
12
13
14 package com.addthis.codec.jackson;
15
16 import java.util.Collection;
17
18 import com.addthis.codec.plugins.PluginMap;
19 import com.addthis.codec.plugins.PluginRegistry;
20 import com.addthis.codec.plugins.Plugins;
21
22 import com.google.common.collect.BiMap;
23 import com.google.common.collect.HashBiMap;
24 import com.google.common.collect.ImmutableBiMap;
25 import com.google.common.collect.Maps;
26
27 import com.fasterxml.jackson.annotation.JsonTypeInfo;
28 import com.fasterxml.jackson.databind.DatabindContext;
29 import com.fasterxml.jackson.databind.JavaType;
30 import com.fasterxml.jackson.databind.jsontype.NamedType;
31 import com.fasterxml.jackson.databind.jsontype.impl.TypeIdResolverBase;
32 import com.fasterxml.jackson.databind.type.TypeFactory;
33
34 public class CodecTypeIdResolver extends TypeIdResolverBase {
35 private final PluginMap pluginMap;
36 private final BiMap<String, Class<?>> extraSubTypes;
37 private final PluginRegistry pluginRegistry;
38
39 public CodecTypeIdResolver(PluginMap pluginMap, JavaType baseType,
40 TypeFactory typeFactory, Collection<NamedType> subtypes,
41 PluginRegistry pluginRegistry) {
42 super(baseType, typeFactory);
43 this.pluginRegistry = pluginRegistry;
44 if (!subtypes.isEmpty()) {
45 BiMap<String, Class<?>> mutableExtraSubTypes = HashBiMap.create(subtypes.size());
46 for (NamedType namedType : subtypes) {
47 if (namedType.hasName()) {
48 mutableExtraSubTypes.put(namedType.getName(), namedType.getType());
49 }
50 }
51 this.extraSubTypes = Maps.unmodifiableBiMap(mutableExtraSubTypes);
52 } else {
53 this.extraSubTypes = ImmutableBiMap.of();
54 }
55 this.pluginMap = pluginMap;
56 }
57
58 public boolean isValidTypeId(String typeId) {
59 Class<?> cls = pluginMap.getClassIfConfigured(typeId);
60 if (cls == null) {
61 cls = extraSubTypes.get(typeId);
62 }
63 try {
64 if (cls == null) {
65 cls = pluginMap.getClass(typeId);
66 }
67 } catch (ClassNotFoundException ignored) {
68 return false;
69 }
70 return _baseType.getRawClass().isAssignableFrom(cls);
71 }
72
73 @Override
74 public JavaType typeFromId(DatabindContext context, String id) {
75 return _typeFromId(id, context.getTypeFactory());
76 }
77
78 @Override public String idFromValue(Object value) {
79 return pluginMap.getClassName(value.getClass());
80 }
81
82 @Override public String idFromValueAndType(Object value, Class<?> suggestedType) {
83 String alt = pluginMap.asBiMap().inverse().get(suggestedType);
84 if (alt != null) {
85 return alt;
86 }
87 if (extraSubTypes.containsValue(suggestedType)) {
88 return extraSubTypes.inverse().get(suggestedType);
89 }
90 return pluginMap.getClassName(suggestedType);
91 }
92
93 @Override public JavaType typeFromId(String id) {
94 return _typeFromId(id, _typeFactory);
95 }
96
97 @Override public JsonTypeInfo.Id getMechanism() {
98 return JsonTypeInfo.Id.CUSTOM;
99 }
100
101 private JavaType _typeFromId(String id, TypeFactory typeFactory) {
102 if (id == null) {
103 return null;
104 }
105 Class<?> cls = pluginMap.getClassIfConfigured(id);
106 if (cls == null) {
107 cls = extraSubTypes.get(id);
108 }
109 try {
110 if (cls == null) {
111 cls = pluginMap.getClass(id);
112 }
113 return typeFactory.constructSpecializedType(_baseType, cls);
114 } catch (Exception e) {
115 String helpMessage = Plugins.classNameSuggestions(pluginRegistry, pluginMap, id);
116 throw new IllegalArgumentException(helpMessage, e);
117 }
118 }
119 }