View Javadoc
1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
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 }