Skip to content

Commit ff42202

Browse files
authored
Third part of #4907: change ordering of serializer lookups to defer introspection further (#5172)
1 parent 80a41e6 commit ff42202

File tree

4 files changed

+92
-96
lines changed

4 files changed

+92
-96
lines changed

src/main/java/tools/jackson/databind/ser/BasicSerializerFactory.java

Lines changed: 17 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package tools.jackson.databind.ser;
22

3-
import java.math.BigDecimal;
4-
import java.math.BigInteger;
53
import java.net.InetAddress;
64
import java.net.InetSocketAddress;
75
import java.nio.ByteBuffer;
@@ -50,51 +48,6 @@ public abstract class BasicSerializerFactory
5048
extends SerializerFactory
5149
implements java.io.Serializable
5250
{
53-
/*
54-
/**********************************************************************
55-
/* Configuration, lookup tables/maps
56-
/**********************************************************************
57-
*/
58-
59-
/**
60-
* Since these are all JDK classes, we shouldn't have to worry
61-
* about ClassLoader used to load them. Rather, we can just
62-
* use the class name, and keep things simple and efficient.
63-
*/
64-
protected final static HashMap<String, ValueSerializer<?>> _concrete;
65-
66-
static {
67-
HashMap<String, ValueSerializer<?>> concrete
68-
= new HashMap<String, ValueSerializer<?>>();
69-
70-
71-
/* String and string-like types (note: date types explicitly
72-
* not included -- can use either textual or numeric serialization)
73-
*/
74-
concrete.put(String.class.getName(), StringSerializer.instance);
75-
final ToStringSerializer sls = ToStringSerializer.instance;
76-
concrete.put(StringBuffer.class.getName(), sls);
77-
concrete.put(StringBuilder.class.getName(), sls);
78-
concrete.put(Character.class.getName(), sls);
79-
concrete.put(Character.TYPE.getName(), sls);
80-
81-
// Primitives/wrappers for primitives (primitives needed for Beans)
82-
NumberSerializers.addAll(concrete);
83-
concrete.put(Boolean.TYPE.getName(), new BooleanSerializer(true));
84-
concrete.put(Boolean.class.getName(), new BooleanSerializer(false));
85-
86-
// Other numbers, more complicated
87-
concrete.put(BigInteger.class.getName(), new NumberSerializer(BigInteger.class));
88-
concrete.put(BigDecimal.class.getName(), new NumberSerializer(BigDecimal.class));
89-
90-
// Other discrete non-container types:
91-
// First, Date/Time zoo:
92-
concrete.put(Calendar.class.getName(), JavaUtilCalendarSerializer.instance);
93-
concrete.put(java.util.Date.class.getName(), JavaUtilDateSerializer.instance);
94-
95-
_concrete = concrete;
96-
}
97-
9851
/*
9952
/**********************************************************************
10053
/* Configuration
@@ -277,27 +230,10 @@ public TypeSerializer findPropertyContentTypeSerializer(SerializationContext ctx
277230

278231
/*
279232
/**********************************************************************
280-
/* Overridable secondary serializer accessor methods
233+
/* Secondary serializer accessor methods
281234
/**********************************************************************
282235
*/
283236

284-
/**
285-
* Method that will use fast lookup (and identity comparison) methods to
286-
* see if we know serializer to use for given type.
287-
*/
288-
protected final ValueSerializer<?> findSerializerByLookup(JavaType type,
289-
SerializationConfig config, BeanDescription.Supplier beanDescRef,
290-
JsonFormat.Value format, boolean staticTyping)
291-
{
292-
final Class<?> raw = type.getRawClass();
293-
ValueSerializer<?> ser = JDKMiscSerializers.find(raw);
294-
if (ser == null) {
295-
final String clsName = raw.getName();
296-
ser = _concrete.get(clsName);
297-
}
298-
return ser;
299-
}
300-
301237
/**
302238
* Method called to see if one of primary per-class annotations
303239
* (or related, like implementing of {@link JacksonSerializable})
@@ -347,15 +283,28 @@ protected final ValueSerializer<?> findSerializerByPrimaryType(SerializationCont
347283
JavaType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
348284
boolean staticTyping)
349285
{
286+
// First: simple lookups for concrete types
287+
final Class<?> raw = type.getRawClass();
288+
ValueSerializer<?> ser;
289+
290+
if ((ser = JDKCoreSerializers.find(raw)) != null) {
291+
return ser;
292+
}
293+
if ((ser = JDKStringLikeSerializer.find(raw)) != null) {
294+
return ser;
295+
}
296+
if ((ser = JDKMiscSerializers.find(raw)) != null) {
297+
return ser;
298+
}
299+
350300
if (type.isTypeOrSubTypeOf(Calendar.class)) {
351301
return JavaUtilCalendarSerializer.instance;
352302
}
353303
if (type.isTypeOrSubTypeOf(Date.class)) {
354304
// 06-Nov-2020, tatu: Strange precedence challenge; need to consider
355305
// "java.sql.Date" unfortunately
356306
if (!type.hasRawClass(Date.class)) {
357-
ValueSerializer<?> ser = OptionalHandlerFactory.instance.findSerializer(ctxt.getConfig(), type);
358-
if (ser != null) {
307+
if ((ser = OptionalHandlerFactory.instance.findSerializer(ctxt.getConfig(), type) ) != null) {
359308
return ser;
360309
}
361310
}
@@ -382,12 +331,7 @@ protected final ValueSerializer<?> findSerializerByPrimaryType(SerializationCont
382331
}
383332
return NumberSerializer.instance;
384333
}
385-
if (type.isEnumType()) {
386-
return buildEnumSerializer(ctxt, type, beanDescRef,
387-
_calculateEffectiveFormat(beanDescRef, Enum.class, formatOverrides));
388-
}
389-
Class<?> raw = type.getRawClass();
390-
if (Map.Entry.class.isAssignableFrom(raw)) {
334+
if (type.isTypeOrSubTypeOf(Map.Entry.class)) {
391335
// 18-Oct-2015, tatu: With 2.7, need to dig type info:
392336
JavaType mapEntryType = type.findSuperType(Map.Entry.class);
393337
// 28-Apr-2015, tatu: TypeFactory does it all for us already so

src/main/java/tools/jackson/databind/ser/BeanSerializerFactory.java

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -207,48 +207,48 @@ protected ValueSerializer<?> _createSerializer2(SerializationContext ctxt,
207207
formatOverrides, staticTyping);
208208
} else if (type.isEnumType()) {
209209
for (Serializers serializers : customSerializers()) {
210-
ser = serializers.findEnumSerializer(config, type, beanDescRef, formatOverrides);
211-
if (ser != null) {
210+
if ((ser = serializers.findEnumSerializer(config, type, beanDescRef, formatOverrides)) != null) {
212211
break;
213212
}
214213
}
215214
} else if (type.isTypeOrSubTypeOf(TreeNode.class)) {
216215
for (Serializers serializers : customSerializers()) {
217-
ser = serializers.findTreeNodeSerializer(config, type, beanDescRef, formatOverrides);
218-
if (ser != null) {
216+
if ((ser = serializers.findTreeNodeSerializer(config, type, beanDescRef, formatOverrides)) != null) {
219217
break;
220218
}
221219
}
222220
} else {
223221
// Modules may provide serializers of POJO types:
224222
for (Serializers serializers : customSerializers()) {
225-
ser = serializers.findSerializer(config, type, beanDescRef, formatOverrides);
226-
if (ser != null) {
223+
if ((ser = serializers.findSerializer(config, type, beanDescRef, formatOverrides)) != null) {
227224
break;
228225
}
229226
}
230227
}
231-
// 25-Jun-2015, tatu: Then JacksonSerializable, @JsonValue etc. NOTE! Prior to 2.6,
232-
// this call was BEFORE custom serializer lookup, which was wrong.
233-
if (ser == null) {
234-
ser = findSerializerByAnnotations(ctxt, type, beanDescRef);
235-
}
236228
}
237229

238230
if (ser == null) {
239231
// Otherwise, we will check "primary types"; main types that have
240232
// precedence over POJO handling
241-
ser = findSerializerByLookup(type, config, beanDescRef, formatOverrides, staticTyping);
233+
ser = findSerializerByPrimaryType(ctxt, type, beanDescRef, formatOverrides, staticTyping);
242234
if (ser == null) {
243-
ser = findSerializerByPrimaryType(ctxt, type, beanDescRef, formatOverrides, staticTyping);
235+
// Then JacksonSerializable, @JsonValue etc.
236+
ser = findSerializerByAnnotations(ctxt, type, beanDescRef);
244237
if (ser == null) {
245-
// And this is where this class comes in: if type is not a
246-
// known "primary JDK type", perhaps it's a bean? We can still
247-
// get a null, if we can't find a single suitable bean property.
248-
ser = constructBeanOrAddOnSerializer(ctxt, type, beanDescRef, formatOverrides, staticTyping);
249-
// Finally: maybe we can still deal with it as an implementation of some basic JDK interface?
238+
// ... but annotations lookup must predate Enum lookup
239+
if (type.isEnumType()) {
240+
// NOTE: may still return `null` (with Shape override)
241+
ser = buildEnumSerializer(ctxt, type, beanDescRef,
242+
_calculateEffectiveFormat(beanDescRef, Enum.class, formatOverrides));
243+
}
250244
if (ser == null) {
251-
ser = ctxt.getUnknownTypeSerializer(beanDescRef.getBeanClass());
245+
// And this is where this class comes in: if type is not a
246+
// known "primary JDK type", perhaps it's a POJO (aka Bean)?
247+
// We can still get a null, for various reasons
248+
ser = constructBeanOrAddOnSerializer(ctxt, type, beanDescRef, formatOverrides, staticTyping);
249+
if (ser == null) {
250+
ser = ctxt.getUnknownTypeSerializer(beanDescRef.getBeanClass());
251+
}
252252
}
253253
}
254254
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package tools.jackson.databind.ser.jdk;
2+
3+
import java.math.BigDecimal;
4+
import java.math.BigInteger;
5+
import java.util.HashMap;
6+
7+
import tools.jackson.databind.ValueSerializer;
8+
import tools.jackson.databind.ser.BasicSerializerFactory;
9+
import tools.jackson.databind.ser.std.ToStringSerializer;
10+
11+
/**
12+
* Set of serializers for JDK core types.
13+
*
14+
* @since 3.0
15+
*/
16+
public class JDKCoreSerializers
17+
{
18+
/**
19+
* Since these are all JDK classes, we shouldn't have to worry
20+
* about ClassLoader used to load them. Rather, we can just
21+
* use the class name, and keep things simple and efficient.
22+
*/
23+
protected final static HashMap<String, ValueSerializer<?>> _concrete;
24+
25+
static {
26+
HashMap<String, ValueSerializer<?>> concrete = new HashMap<>();
27+
28+
// String and string-like types (note: date types explicitly
29+
// not included -- can use either textual or numeric serialization)
30+
concrete.put(String.class.getName(), StringSerializer.instance);
31+
final ToStringSerializer sls = ToStringSerializer.instance;
32+
concrete.put(StringBuffer.class.getName(), sls);
33+
concrete.put(StringBuilder.class.getName(), sls);
34+
concrete.put(Character.class.getName(), sls);
35+
concrete.put(Character.TYPE.getName(), sls);
36+
37+
// Primitives/wrappers for primitives (primitives needed for Beans)
38+
NumberSerializers.addAll(concrete);
39+
concrete.put(Boolean.TYPE.getName(), new BooleanSerializer(true));
40+
concrete.put(Boolean.class.getName(), new BooleanSerializer(false));
41+
42+
// Other numbers, more complicated
43+
concrete.put(BigInteger.class.getName(), new NumberSerializer(BigInteger.class));
44+
concrete.put(BigDecimal.class.getName(), new NumberSerializer(BigDecimal.class));
45+
46+
_concrete = concrete;
47+
}
48+
49+
/**
50+
* Method called by {@link BasicSerializerFactory} to find one of serializers provided here.
51+
*/
52+
public static final ValueSerializer<?> find(Class<?> raw)
53+
{
54+
return _concrete.get(raw.getName());
55+
}
56+
}

src/main/java/tools/jackson/databind/ser/jdk/JDKMiscSerializers.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ public class JDKMiscSerializers
2626
*/
2727
public static final ValueSerializer<?> find(Class<?> raw)
2828
{
29-
ValueSerializer<?> ser = JDKStringLikeSerializer.find(raw);
30-
if (ser != null) {
31-
return ser;
32-
}
3329
if (raw == UUID.class) {
3430
return new UUIDSerializer();
3531
}

0 commit comments

Comments
 (0)