Skip to content

Commit c3fdb53

Browse files
committed
Minor refactoring: move RootNameLookup deeper into configs, to reduce state to copy for ObjectReader
1 parent c4b695c commit c3fdb53

File tree

10 files changed

+226
-110
lines changed

10 files changed

+226
-110
lines changed

src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@
66
import com.fasterxml.jackson.annotation.JsonAutoDetect;
77
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
88
import com.fasterxml.jackson.annotation.PropertyAccessor;
9-
109
import com.fasterxml.jackson.core.*;
11-
1210
import com.fasterxml.jackson.databind.cfg.*;
1311
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
1412
import com.fasterxml.jackson.databind.introspect.*;
1513
import com.fasterxml.jackson.databind.jsontype.*;
1614
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
1715
import com.fasterxml.jackson.databind.type.TypeFactory;
1816
import com.fasterxml.jackson.databind.util.LinkedNode;
17+
import com.fasterxml.jackson.databind.util.RootNameLookup;
1918

2019
/**
2120
* Object that contains baseline configuration for deserialization
@@ -25,9 +24,6 @@
2524
* Note that instances are considered immutable and as such no copies
2625
* should need to be created for sharing; all copying is done with
2726
* "fluent factory" methods.
28-
* Note also that unlike with Jackson 1, these instances can not be
29-
* assigned to {@link ObjectMapper}; in fact, application code should
30-
* rarely interact directly with these instances.
3127
*/
3228
public final class DeserializationConfig
3329
extends MapperConfigBase<DeserializationFeature, DeserializationConfig>
@@ -73,9 +69,10 @@ public final class DeserializationConfig
7369
* Constructor used by ObjectMapper to create default configuration object instance.
7470
*/
7571
public DeserializationConfig(BaseSettings base,
76-
SubtypeResolver str, SimpleMixInResolver mixins)
72+
SubtypeResolver str, SimpleMixInResolver mixins,
73+
RootNameLookup rootNames)
7774
{
78-
super(base, str, mixins);
75+
super(base, str, mixins, rootNames);
7976
_deserFeatures = collectFeatureDefaults(DeserializationFeature.class);
8077
_nodeFactory = JsonNodeFactory.instance;
8178
_problemHandlers = null;
@@ -140,7 +137,7 @@ private DeserializationConfig(DeserializationConfig src,
140137
_parserFeaturesToChange = src._parserFeaturesToChange;
141138
}
142139

143-
private DeserializationConfig(DeserializationConfig src, String rootName)
140+
private DeserializationConfig(DeserializationConfig src, PropertyName rootName)
144141
{
145142
super(src, rootName);
146143
_deserFeatures = src._deserFeatures;
@@ -160,6 +157,19 @@ private DeserializationConfig(DeserializationConfig src, Class<?> view)
160157
_parserFeaturesToChange = src._parserFeaturesToChange;
161158
}
162159

160+
/**
161+
* @since 2.3
162+
*/
163+
protected DeserializationConfig(DeserializationConfig src, ContextAttributes attrs)
164+
{
165+
super(src, attrs);
166+
_deserFeatures = src._deserFeatures;
167+
_problemHandlers = src._problemHandlers;
168+
_nodeFactory = src._nodeFactory;
169+
_parserFeatures = src._parserFeatures;
170+
_parserFeaturesToChange = src._parserFeaturesToChange;
171+
}
172+
163173
/**
164174
* @since 2.1
165175
*/
@@ -172,13 +182,17 @@ protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver m
172182
_parserFeatures = src._parserFeatures;
173183
_parserFeaturesToChange = src._parserFeaturesToChange;
174184
}
175-
185+
176186
/**
177-
* @since 2.3
187+
* Copy-constructor used for making a copy to be used by new {@link ObjectMapper}
188+
* or {@link ObjectReader}.
189+
*
190+
* @since 2.6
178191
*/
179-
protected DeserializationConfig(DeserializationConfig src, ContextAttributes attrs)
192+
protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver mixins,
193+
RootNameLookup rootNames)
180194
{
181-
super(src, attrs);
195+
super(src, mixins, rootNames);
182196
_deserFeatures = src._deserFeatures;
183197
_problemHandlers = src._problemHandlers;
184198
_nodeFactory = src._nodeFactory;
@@ -270,7 +284,7 @@ public DeserializationConfig with(PropertyNamingStrategy pns) {
270284
}
271285

272286
@Override
273-
public DeserializationConfig withRootName(String rootName) {
287+
public DeserializationConfig withRootName(PropertyName rootName) {
274288
if (rootName == null) {
275289
if (_rootName == null) {
276290
return this;
@@ -280,7 +294,7 @@ public DeserializationConfig withRootName(String rootName) {
280294
}
281295
return new DeserializationConfig(this, rootName);
282296
}
283-
297+
284298
@Override
285299
public DeserializationConfig with(TypeFactory tf) {
286300
return _withBase( _base.withTypeFactory(tf));
@@ -595,7 +609,7 @@ public AnnotationIntrospector getAnnotationIntrospector()
595609
public boolean useRootWrapping()
596610
{
597611
if (_rootName != null) { // empty String disables wrapping; non-empty enables
598-
return (_rootName.length() > 0);
612+
return !_rootName.isEmpty();
599613
}
600614
return isEnabled(DeserializationFeature.UNWRAP_ROOT_VALUE);
601615
}

src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,6 @@ public boolean useForType(JavaType t)
311311
*/
312312
protected SubtypeResolver _subtypeResolver;
313313

314-
/**
315-
* Cache for root names used when root-wrapping is enabled.
316-
*/
317-
protected final RootNameLookup _rootNames;
318-
319314
/*
320315
/**********************************************************
321316
/* Configuration settings: mix-in annotations
@@ -473,14 +468,14 @@ protected ObjectMapper(ObjectMapper src)
473468
_jsonFactory = src._jsonFactory.copy();
474469
_jsonFactory.setCodec(this);
475470
_subtypeResolver = src._subtypeResolver;
476-
_rootNames = new RootNameLookup();
477471
_typeFactory = src._typeFactory;
478472
_injectableValues = src._injectableValues;
479473

480474
SimpleMixInResolver mixins = src._mixIns.copy();
481475
_mixIns = mixins;
482-
_serializationConfig = new SerializationConfig(src._serializationConfig, mixins);
483-
_deserializationConfig = new DeserializationConfig(src._deserializationConfig, mixins);
476+
RootNameLookup rootNames = new RootNameLookup();
477+
_serializationConfig = new SerializationConfig(src._serializationConfig, mixins, rootNames);
478+
_deserializationConfig = new DeserializationConfig(src._deserializationConfig, mixins, rootNames);
484479
_serializerProvider = src._serializerProvider.copy();
485480
_deserializationContext = src._deserializationContext.copy();
486481

@@ -518,7 +513,7 @@ public ObjectMapper(JsonFactory jf,
518513
}
519514
}
520515
_subtypeResolver = new StdSubtypeResolver();
521-
_rootNames = new RootNameLookup();
516+
RootNameLookup rootNames = new RootNameLookup();
522517
// and default type factory is shared one
523518
_typeFactory = TypeFactory.defaultInstance();
524519

@@ -527,9 +522,9 @@ public ObjectMapper(JsonFactory jf,
527522

528523
BaseSettings base = DEFAULT_BASE.withClassIntrospector(defaultClassIntrospector());
529524
_serializationConfig = new SerializationConfig(base,
530-
_subtypeResolver, mixins);
525+
_subtypeResolver, mixins, rootNames);
531526
_deserializationConfig = new DeserializationConfig(base,
532-
_subtypeResolver, mixins);
527+
_subtypeResolver, mixins, rootNames);
533528

534529
// Some overrides we may need
535530
final boolean needOrder = _jsonFactory.requiresPropertyOrdering();
@@ -3760,31 +3755,29 @@ protected Object _unwrapAndDeserialize(JsonParser p, DeserializationContext ctxt
37603755
JavaType rootType, JsonDeserializer<Object> deser)
37613756
throws IOException
37623757
{
3763-
String expName = config.getRootName();
3764-
if (expName == null) {
3765-
PropertyName pname = _rootNames.findRootName(rootType, config);
3766-
expName = pname.getSimpleName();
3767-
}
3758+
PropertyName expRootName = config.findRootName(rootType);
3759+
// 12-Jun-2015, tatu: Should try to support namespaces etc but...
3760+
String expSimpleName = expRootName.getSimpleName();
37683761
if (p.getCurrentToken() != JsonToken.START_OBJECT) {
37693762
throw JsonMappingException.from(p, "Current token not START_OBJECT (needed to unwrap root name '"
3770-
+expName+"'), but "+p.getCurrentToken());
3763+
+expSimpleName+"'), but "+p.getCurrentToken());
37713764
}
37723765
if (p.nextToken() != JsonToken.FIELD_NAME) {
37733766
throw JsonMappingException.from(p, "Current token not FIELD_NAME (to contain expected root name '"
3774-
+expName+"'), but "+p.getCurrentToken());
3767+
+expSimpleName+"'), but "+p.getCurrentToken());
37753768
}
37763769
String actualName = p.getCurrentName();
3777-
if (!expName.equals(actualName)) {
3770+
if (!expSimpleName.equals(actualName)) {
37783771
throw JsonMappingException.from(p, "Root name '"+actualName+"' does not match expected ('"
3779-
+expName+"') for type "+rootType);
3772+
+expSimpleName+"') for type "+rootType);
37803773
}
37813774
// ok, then move to value itself....
37823775
p.nextToken();
37833776
Object result = deser.deserialize(p, ctxt);
37843777
// and last, verify that we now get matching END_OBJECT
37853778
if (p.nextToken() != JsonToken.END_OBJECT) {
37863779
throw JsonMappingException.from(p, "Current token not END_OBJECT (to match wrapper object with root name '"
3787-
+expName+"'), but "+p.getCurrentToken());
3780+
+expSimpleName+"'), but "+p.getCurrentToken());
37883781
}
37893782
return result;
37903783
}

src/main/java/com/fasterxml/jackson/databind/ObjectReader.java

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@
2020
import com.fasterxml.jackson.databind.node.TreeTraversingParser;
2121
import com.fasterxml.jackson.databind.type.SimpleType;
2222
import com.fasterxml.jackson.databind.type.TypeFactory;
23-
import com.fasterxml.jackson.databind.util.RootNameLookup;
2423

2524
/**
2625
* Builder object that can be used for per-serialization configuration of
2726
* deserialization parameters, such as root type to use or object
2827
* to update (instead of constructing new instance).
2928
*<p>
30-
* Uses "fluent" (or, kind of, builder) pattern so that instances are immutable
29+
* Uses "mutant factory" pattern so that instances are immutable
3130
* (and thus fully thread-safe with no external synchronization);
3231
* new instances are constructed for different configurations.
3332
* Instances are initially constructed by {@link ObjectMapper} and can be
@@ -143,12 +142,6 @@ public class ObjectReader
143142
*/
144143
final protected ConcurrentHashMap<JavaType, JsonDeserializer<Object>> _rootDeserializers;
145144

146-
/**
147-
* Cache for root names used when root-wrapping is enabled.
148-
* Passed by {@link ObjectMapper}, shared with it.
149-
*/
150-
protected final RootNameLookup _rootNames;
151-
152145
/*
153146
/**********************************************************
154147
/* Life-cycle, construction
@@ -174,7 +167,6 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,
174167
_context = mapper._deserializationContext;
175168
_rootDeserializers = mapper._rootDeserializers;
176169
_parserFactory = mapper._jsonFactory;
177-
_rootNames = mapper._rootNames;
178170
_valueType = valueType;
179171
_valueToUpdate = valueToUpdate;
180172
if (valueToUpdate != null && valueType.isArrayType()) {
@@ -201,7 +193,6 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config,
201193

202194
_rootDeserializers = base._rootDeserializers;
203195
_parserFactory = base._parserFactory;
204-
_rootNames = base._rootNames;
205196

206197
_valueType = valueType;
207198
_rootDeserializer = rootDeser;
@@ -225,7 +216,6 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config)
225216

226217
_rootDeserializers = base._rootDeserializers;
227218
_parserFactory = base._parserFactory;
228-
_rootNames = base._rootNames;
229219

230220
_valueType = base._valueType;
231221
_rootDeserializer = base._rootDeserializer;
@@ -245,7 +235,6 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
245235

246236
_rootDeserializers = base._rootDeserializers;
247237
_parserFactory = f;
248-
_rootNames = base._rootNames;
249238

250239
_valueType = base._valueType;
251240
_rootDeserializer = base._rootDeserializer;
@@ -537,6 +526,13 @@ public ObjectReader withRootName(String rootName) {
537526
return _with(_config.withRootName(rootName));
538527
}
539528

529+
/**
530+
* @since 2.6
531+
*/
532+
public ObjectReader withRootName(PropertyName rootName) {
533+
return _with(_config.withRootName(rootName));
534+
}
535+
540536
/**
541537
* Convenience method that is same as calling:
542538
*<code>
@@ -548,7 +544,7 @@ public ObjectReader withRootName(String rootName) {
548544
* @since 2.6
549545
*/
550546
public ObjectReader withoutRootName() {
551-
return _with(_config.withRootName(""));
547+
return _with(_config.withRootName(PropertyName.NO_NAME));
552548
}
553549

554550
/**
@@ -1521,23 +1517,22 @@ protected <T> MappingIterator<T> _bindAndReadValues(JsonParser p, Object valueTo
15211517
protected Object _unwrapAndDeserialize(JsonParser jp, DeserializationContext ctxt,
15221518
JavaType rootType, JsonDeserializer<Object> deser) throws IOException
15231519
{
1524-
String expName = _config.getRootName();
1525-
if (expName == null) {
1526-
PropertyName pname = _rootNames.findRootName(rootType, _config);
1527-
expName = pname.getSimpleName();
1528-
}
1520+
PropertyName expRootName = _config.findRootName(rootType);
1521+
// 12-Jun-2015, tatu: Should try to support namespaces etc but...
1522+
String expSimpleName = expRootName.getSimpleName();
1523+
15291524
if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
15301525
throw JsonMappingException.from(jp, "Current token not START_OBJECT (needed to unwrap root name '"
1531-
+expName+"'), but "+jp.getCurrentToken());
1526+
+expSimpleName+"'), but "+jp.getCurrentToken());
15321527
}
15331528
if (jp.nextToken() != JsonToken.FIELD_NAME) {
15341529
throw JsonMappingException.from(jp, "Current token not FIELD_NAME (to contain expected root name '"
1535-
+expName+"'), but "+jp.getCurrentToken());
1530+
+expSimpleName+"'), but "+jp.getCurrentToken());
15361531
}
15371532
String actualName = jp.getCurrentName();
1538-
if (!expName.equals(actualName)) {
1533+
if (!expSimpleName.equals(actualName)) {
15391534
throw JsonMappingException.from(jp, "Root name '"+actualName+"' does not match expected ('"
1540-
+expName+"') for type "+rootType);
1535+
+expSimpleName+"') for type "+rootType);
15411536
}
15421537
// ok, then move to value itself....
15431538
jp.nextToken();
@@ -1551,7 +1546,7 @@ protected Object _unwrapAndDeserialize(JsonParser jp, DeserializationContext ctx
15511546
// and last, verify that we now get matching END_OBJECT
15521547
if (jp.nextToken() != JsonToken.END_OBJECT) {
15531548
throw JsonMappingException.from(jp, "Current token not END_OBJECT (to match wrapper object with root name '"
1554-
+expName+"'), but "+jp.getCurrentToken());
1549+
+expSimpleName+"'), but "+jp.getCurrentToken());
15551550
}
15561551
return result;
15571552
}

src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class ObjectWriter
3737
* easiest to do by a token value.
3838
*/
3939
protected final static PrettyPrinter NULL_PRETTY_PRINTER = new MinimalPrettyPrinter();
40-
40+
4141
/*
4242
/**********************************************************
4343
/* Immutable configuration from ObjectMapper
@@ -48,7 +48,7 @@ public class ObjectWriter
4848
* General serialization configuration settings
4949
*/
5050
protected final SerializationConfig _config;
51-
51+
5252
protected final DefaultSerializerProvider _serializerProvider;
5353

5454
protected final SerializerFactory _serializerFactory;
@@ -413,6 +413,14 @@ public ObjectWriter withRootName(String rootName) {
413413
return (newConfig == _config) ? this : _new(this, newConfig);
414414
}
415415

416+
/**
417+
* @since 2.6
418+
*/
419+
public ObjectWriter withRootName(PropertyName rootName) {
420+
SerializationConfig newConfig = _config.withRootName(rootName);
421+
return (newConfig == _config) ? this : _new(this, newConfig);
422+
}
423+
416424
/**
417425
* Convenience method that is same as calling:
418426
*<code>
@@ -424,7 +432,7 @@ public ObjectWriter withRootName(String rootName) {
424432
* @since 2.6
425433
*/
426434
public ObjectWriter withoutRootName() {
427-
SerializationConfig newConfig = _config.withRootName("");
435+
SerializationConfig newConfig = _config.withRootName(PropertyName.NO_NAME);
428436
return (newConfig == _config) ? this : _new(this, newConfig);
429437
}
430438

0 commit comments

Comments
 (0)