1
2
3
4
5
6
7
8
9
10
11
12
13
14 package com.addthis.codec.jackson;
15
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.Map;
19
20 import com.addthis.codec.annotations.FieldConfig;
21 import com.addthis.codec.annotations.Pluggable;
22 import com.addthis.codec.plugins.PluginMap;
23 import com.addthis.codec.plugins.PluginRegistry;
24
25 import com.fasterxml.jackson.databind.JavaType;
26 import com.fasterxml.jackson.databind.PropertyName;
27 import com.fasterxml.jackson.databind.cfg.MapperConfig;
28 import com.fasterxml.jackson.databind.introspect.Annotated;
29 import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
30 import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
31 import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
32 import com.fasterxml.jackson.databind.jsontype.NamedType;
33 import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 public class CodecIntrospector extends NopAnnotationIntrospector {
39 private static final Logger log = LoggerFactory.getLogger(CodecIntrospector.class);
40
41 private final PluginRegistry pluginRegistry;
42
43 public CodecIntrospector(PluginRegistry pluginRegistry) {
44 this.pluginRegistry = pluginRegistry;
45 }
46
47 @Override
48 public TypeResolverBuilder<?> findTypeResolver(MapperConfig<?> config, AnnotatedClass ac, JavaType baseType) {
49 Pluggable pluggable = ac.getAnnotation(Pluggable.class);
50 if (pluggable != null) {
51 PluginMap pluginMap = pluginRegistry.byCategory().get(pluggable.value());
52 if (pluginMap != null) {
53 return new CodecTypeResolverBuilder(pluginMap, config.getTypeFactory(), pluginRegistry);
54 } else {
55 log.warn("missing plugin map for {}, reached from {}", pluggable.value(), ac.getRawType());
56 }
57 } else if (pluginRegistry.byClass().containsKey(ac.getRawType())) {
58 PluginMap pluginMap = pluginRegistry.byClass().get(ac.getRawType());
59 return new CodecTypeResolverBuilder(pluginMap, config.getTypeFactory(), pluginRegistry);
60 }
61 return null;
62 }
63
64
65 @Override
66 public List<NamedType> findSubtypes(Annotated a) {
67 Pluggable pluggable = a.getAnnotation(Pluggable.class);
68 PluginMap pluginMap;
69 if (pluggable != null) {
70 pluginMap = pluginRegistry.byCategory().get(pluggable.value());
71 } else if (pluginRegistry.byClass().containsKey(a.getRawType())) {
72 pluginMap = pluginRegistry.byClass().get(a.getRawType());
73 } else {
74 return null;
75 }
76 List<NamedType> result = new ArrayList<>(pluginMap.asBiMap().size());
77 for (Map.Entry<String, Class<?>> type : pluginMap.asBiMap().entrySet()) {
78 result.add(new NamedType(type.getValue(), type.getKey()));
79 }
80 return result;
81 }
82
83 @Override
84 public boolean hasIgnoreMarker(AnnotatedMember m) {
85 FieldConfig fieldConfig = m.getAnnotation(FieldConfig.class);
86 if (fieldConfig != null) {
87 return !fieldConfig.codable();
88 }
89 return false;
90 }
91
92 @Override
93 public Boolean hasRequiredMarker(AnnotatedMember m) {
94 FieldConfig fieldConfig = m.getAnnotation(FieldConfig.class);
95 if (fieldConfig != null) {
96 return fieldConfig.required();
97 }
98 return null;
99 }
100
101
102
103
104
105 @Override
106 public PropertyName findNameForDeserialization(Annotated a) {
107 FieldConfig fieldConfig = a.getAnnotation(FieldConfig.class);
108 if ((fieldConfig != null) && !fieldConfig.writeonly() && fieldConfig.codable()) {
109 return PropertyName.USE_DEFAULT;
110 }
111 return null;
112 }
113
114 @Override
115 public PropertyName findNameForSerialization(Annotated a) {
116 FieldConfig fieldConfig = a.getAnnotation(FieldConfig.class);
117 if ((fieldConfig != null) && !fieldConfig.readonly() && fieldConfig.codable()) {
118 return PropertyName.USE_DEFAULT;
119 }
120 return null;
121 }
122 }