forked from FasterXML/jackson-databind
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathOptionalHandlerFactory.java
More file actions
201 lines (177 loc) · 7.86 KB
/
OptionalHandlerFactory.java
File metadata and controls
201 lines (177 loc) · 7.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package com.fasterxml.jackson.databind.ext;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.Deserializers;
import com.fasterxml.jackson.databind.ser.Serializers;
import com.fasterxml.jackson.databind.util.ClassUtil;
/**
* Helper class used for isolating details of handling optional+external types
* (javax.xml classes) from standard factories that offer them.
*<p>
* Note that 2.7 changed handling to slightly less dynamic, to avoid having to
* traverse class hierarchy, which turned to be a performance issue in
* certain cases. Since DOM classes are assumed to exist on all Java 1.6
* environments (yes, even on Android/GAE), this part could be simplified by
* slightly less dynamic lookups.
*<p>
* Also with 2.7 we are supporting JDK 1.7/Java 7 type(s).
*/
public class OptionalHandlerFactory implements java.io.Serializable
{
private static final long serialVersionUID = 1;
/* To make 2 main "optional" handler groups (javax.xml.stream)
* more dynamic, we better only figure out handlers completely dynamically, if and
* when they are needed. To do this we need to assume package prefixes.
*/
private final static String PACKAGE_PREFIX_JAVAX_XML = "javax.xml.";
private final static String SERIALIZERS_FOR_JAVAX_XML = "com.fasterxml.jackson.databind.ext.CoreXMLSerializers";
private final static String DESERIALIZERS_FOR_JAVAX_XML = "com.fasterxml.jackson.databind.ext.CoreXMLDeserializers";
// Plus we also have a single serializer for DOM Node:
// private final static String CLASS_NAME_DOM_NODE = "org.w3c.dom.Node";
// private final static String CLASS_NAME_DOM_DOCUMENT = "org.w3c.dom.Document";
private final static String SERIALIZER_FOR_DOM_NODE = "com.fasterxml.jackson.databind.ext.DOMSerializer";
private final static String DESERIALIZER_FOR_DOM_DOCUMENT = "com.fasterxml.jackson.databind.ext.DOMDeserializer$DocumentDeserializer";
private final static String DESERIALIZER_FOR_DOM_NODE = "com.fasterxml.jackson.databind.ext.DOMDeserializer$NodeDeserializer";
// // Since 2.7, we will assume DOM classes are always found, both due to JDK 1.6 minimum
// // and because Android (and presumably GAE) have these classes
// // 02-Nov-2020, Xakep_SDK: java.xml module classes may be missing
// // in actual runtime, if module java.xml is not present
private final static Class<?> CLASS_DOM_NODE;
private final static Class<?> CLASS_DOM_DOCUMENT;
static {
Class<?> doc = null, node = null;
try {
node = org.w3c.dom.Node.class;
doc = org.w3c.dom.Document.class;
} catch (Throwable e) {
// not optimal but will do
// 02-Nov-2020, Xakep_SDK: Remove java.logging module dependency
// Logger.getLogger(OptionalHandlerFactory.class.getName())
// .log(Level.INFO, "Could not load DOM `Node` and/or `Document` classes: no DOM support");
}
CLASS_DOM_NODE = node;
CLASS_DOM_DOCUMENT = doc;
}
// // But Java7 type(s) may or may not be; dynamic lookup should be fine, still
// // (note: also assume it comes from JDK so that ClassLoader issues with OSGi
// // can, I hope, be avoided?)
private static final Java7Handlers _jdk7Helper;
static {
Java7Handlers x = null;
try {
x = Java7Handlers.instance();
} catch (Throwable t) { }
_jdk7Helper = x;
}
public final static OptionalHandlerFactory instance = new OptionalHandlerFactory();
protected OptionalHandlerFactory() { }
/*
/**********************************************************
/* Public API
/**********************************************************
*/
public JsonSerializer<?> findSerializer(SerializationConfig config, JavaType type,
BeanDescription beanDesc)
{
final Class<?> rawType = type.getRawClass();
if ((CLASS_DOM_NODE != null) && CLASS_DOM_NODE.isAssignableFrom(rawType)) {
return (JsonSerializer<?>) instantiate(SERIALIZER_FOR_DOM_NODE);
}
if (_jdk7Helper != null) {
JsonSerializer<?> ser = _jdk7Helper.getSerializerForJavaNioFilePath(rawType);
if (ser != null) {
return ser;
}
}
String className = rawType.getName();
String factoryName;
if (className.startsWith(PACKAGE_PREFIX_JAVAX_XML) || hasSuperClassStartingWith(rawType, PACKAGE_PREFIX_JAVAX_XML)) {
factoryName = SERIALIZERS_FOR_JAVAX_XML;
} else {
return null;
}
Object ob = instantiate(factoryName);
if (ob == null) { // could warn, if we had logging system (j.u.l?)
return null;
}
return ((Serializers) ob).findSerializer(config, type, beanDesc);
}
public JsonDeserializer<?> findDeserializer(JavaType type, DeserializationConfig config,
BeanDescription beanDesc)
throws JsonMappingException
{
final Class<?> rawType = type.getRawClass();
if (_jdk7Helper != null) {
JsonDeserializer<?> deser = _jdk7Helper.getDeserializerForJavaNioFilePath(rawType);
if (deser != null) {
return deser;
}
}
if ((CLASS_DOM_NODE != null) && CLASS_DOM_NODE.isAssignableFrom(rawType)) {
return (JsonDeserializer<?>) instantiate(DESERIALIZER_FOR_DOM_NODE);
}
if ((CLASS_DOM_DOCUMENT != null) && CLASS_DOM_DOCUMENT.isAssignableFrom(rawType)) {
return (JsonDeserializer<?>) instantiate(DESERIALIZER_FOR_DOM_DOCUMENT);
}
String className = rawType.getName();
String factoryName;
if (className.startsWith(PACKAGE_PREFIX_JAVAX_XML)
|| hasSuperClassStartingWith(rawType, PACKAGE_PREFIX_JAVAX_XML)) {
factoryName = DESERIALIZERS_FOR_JAVAX_XML;
} else {
return null;
}
Object ob = instantiate(factoryName);
if (ob == null) { // could warn, if we had logging system (j.u.l?)
return null;
}
return ((Deserializers) ob).findBeanDeserializer(type, config, beanDesc);
}
public boolean hasDeserializerFor(Class<?> valueType) {
if ((CLASS_DOM_NODE != null) && CLASS_DOM_NODE.isAssignableFrom(valueType)) {
return true;
}
if ((CLASS_DOM_DOCUMENT != null) && CLASS_DOM_DOCUMENT.isAssignableFrom(valueType)) {
return true;
}
String className = valueType.getName();
if (className.startsWith(PACKAGE_PREFIX_JAVAX_XML)
|| hasSuperClassStartingWith(valueType, PACKAGE_PREFIX_JAVAX_XML)) {
return true;
}
return false;
}
/*
/**********************************************************
/* Internal helper methods
/**********************************************************
*/
private Object instantiate(String className)
{
try {
return ClassUtil.createInstance(Class.forName(className), false);
} catch (LinkageError e) { }
// too many different kinds to enumerate here:
catch (Exception e) { }
return null;
}
/**
* Since 2.7 we only need to check for class extension, as all implemented
* types are classes, not interfaces. This has performance implications for
* some cases, as we do not need to go over interfaces implemented, just
* superclasses
*
* @since 2.7
*/
private boolean hasSuperClassStartingWith(Class<?> rawType, String prefix)
{
for (Class<?> supertype = rawType.getSuperclass(); supertype != null; supertype = supertype.getSuperclass()) {
if (supertype == Object.class) {
return false;
}
if (supertype.getName().startsWith(prefix)) {
return true;
}
}
return false;
}
}