Skip to content

Commit 5ee6591

Browse files
committed
Complete #655 implementation (add ObjectWriter.writeValues())
1 parent a199cbd commit 5ee6591

File tree

8 files changed

+230
-88
lines changed

8 files changed

+230
-88
lines changed

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Project: jackson-databind
6262
(using @JsonAppend, VirtualBeanPropertyWriter)
6363
#647: Deserialization fails when @JsonUnwrapped property contains an object with same property name
6464
(reported by Konstantin L)
65+
#655: Add `ObjectWriter.writeValues()` for writing value sequences
6566
- Allow use of `Shape.ARRAY` for Enums, as an alias to 'use index'
6667
- Start using `JsonGenerator.writeStartArray(int)` to help data formats
6768
that benefit from knowing number of elements in arrays (and would otherwise

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

+127-66
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.fasterxml.jackson.core.util.*;
1313
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
1414
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
15+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
1516
import com.fasterxml.jackson.databind.ser.*;
1617
import com.fasterxml.jackson.databind.type.TypeFactory;
1718

@@ -62,29 +63,23 @@ public class ObjectWriter
6263
*/
6364

6465
/**
65-
* Specified root serialization type to use; can be same
66-
* as runtime type, but usually one of its super types
66+
* Container for settings that need to be passed to {@link JsonGenerator}
67+
* constructed for serializing values.
68+
*
69+
* @since 2.5
6770
*/
68-
protected final JavaType _rootType;
71+
protected final GeneratorSettings _generatorSettings;
6972

7073
/**
7174
* We may pre-fetch serializer if {@link #_rootType}
7275
* is known, and if so, reuse it afterwards.
7376
* This allows avoiding further serializer lookups and increases
7477
* performance a bit on cases where readers are reused.
75-
*
76-
* @since 2.1
77-
*/
78-
protected final JsonSerializer<Object> _rootSerializer;
79-
80-
/**
81-
* Container for settings that need to be passed to {@link JsonGenerator}
82-
* constructed for serializing values.
8378
*
8479
* @since 2.5
8580
*/
86-
protected final GeneratorSettings _generatorSettings;
87-
81+
protected final Prefetch _prefetch;
82+
8883
/*
8984
/**********************************************************
9085
/* Life-cycle, constructors
@@ -106,11 +101,10 @@ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
106101

107102
// 29-Apr-2014, tatu: There is no "untyped serializer", so:
108103
if (rootType == null || rootType.hasRawClass(Object.class)) {
109-
_rootType = null;
110-
_rootSerializer = null;
104+
_prefetch = Prefetch.empty;
111105
} else {
112-
_rootType = rootType.withStaticTyping();
113-
_rootSerializer = _prefetchRootSerializer(config, _rootType);
106+
rootType = rootType.withStaticTyping();
107+
_prefetch = _prefetchRootSerializer(config, rootType);
114108
}
115109
}
116110

@@ -124,8 +118,7 @@ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config)
124118
_serializerFactory = mapper._serializerFactory;
125119
_generatorFactory = mapper._jsonFactory;
126120

127-
_rootType = null;
128-
_rootSerializer = null;
121+
_prefetch = Prefetch.empty;
129122
_generatorSettings = GeneratorSettings.empty;
130123
}
131124

@@ -141,8 +134,7 @@ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
141134
_serializerFactory = mapper._serializerFactory;
142135
_generatorFactory = mapper._jsonFactory;
143136

144-
_rootType = null;
145-
_rootSerializer = null;
137+
_prefetch = Prefetch.empty;
146138
_generatorSettings = (s == null) ? GeneratorSettings.empty
147139
: new GeneratorSettings(null, s, null);
148140
}
@@ -151,18 +143,16 @@ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
151143
* Copy constructor used for building variations.
152144
*/
153145
protected ObjectWriter(ObjectWriter base, SerializationConfig config,
154-
JavaType rootType, JsonSerializer<Object> rootSer,
155-
GeneratorSettings genSettings)
146+
GeneratorSettings genSettings, Prefetch prefetch)
156147
{
157148
_config = config;
158149

159150
_serializerProvider = base._serializerProvider;
160151
_serializerFactory = base._serializerFactory;
161152
_generatorFactory = base._generatorFactory;
162153

163-
_rootType = rootType;
164-
_rootSerializer = rootSer;
165154
_generatorSettings = genSettings;
155+
_prefetch = prefetch;
166156
}
167157

168158
/**
@@ -176,9 +166,7 @@ protected ObjectWriter(ObjectWriter base, SerializationConfig config)
176166
_serializerFactory = base._serializerFactory;
177167
_generatorFactory = base._generatorFactory;
178168
_generatorSettings = base._generatorSettings;
179-
180-
_rootType = base._rootType;
181-
_rootSerializer = base._rootSerializer;
169+
_prefetch = base._prefetch;
182170
}
183171

184172
/**
@@ -194,9 +182,7 @@ protected ObjectWriter(ObjectWriter base, JsonFactory f)
194182
_serializerFactory = base._serializerFactory;
195183
_generatorFactory = base._generatorFactory;
196184
_generatorSettings = base._generatorSettings;
197-
198-
_rootType = base._rootType;
199-
_rootSerializer = base._rootSerializer;
185+
_prefetch = base._prefetch;
200186
}
201187

202188
/**
@@ -241,9 +227,8 @@ protected ObjectWriter _new(ObjectWriter base, SerializationConfig config) {
241227
*
242228
* @since 2.5
243229
*/
244-
protected ObjectWriter _new(JavaType rootType, JsonSerializer<Object> rootSer,
245-
GeneratorSettings genSettings) {
246-
return new ObjectWriter(this, _config, rootType, rootSer, genSettings);
230+
protected ObjectWriter _new(GeneratorSettings genSettings, Prefetch prefetch) {
231+
return new ObjectWriter(this, _config, genSettings, prefetch);
247232
}
248233

249234
/**
@@ -258,7 +243,7 @@ protected SequenceWriter _newSequenceWriter(boolean wrapInArray,
258243
throws IOException
259244
{
260245
return new SequenceWriter(_serializerProvider(_config),
261-
_configureGenerator(gen), managedInput, _rootType, _rootSerializer)
246+
_configureGenerator(gen), managedInput, _prefetch)
262247
.init(wrapInArray);
263248
}
264249

@@ -405,7 +390,7 @@ public ObjectWriter with(PrettyPrinter pp) {
405390
if (genSet == _generatorSettings) {
406391
return this;
407392
}
408-
return _new(_rootType, _rootSerializer, genSet);
393+
return _new(genSet, _prefetch);
409394
}
410395

411396
/**
@@ -434,7 +419,7 @@ public ObjectWriter with(FormatSchema schema) {
434419
return this;
435420
}
436421
_verifySchemaType(schema);
437-
return _new(_rootType, _rootSerializer, genSet);
422+
return _new(genSet, _prefetch);
438423
}
439424

440425
/**
@@ -457,16 +442,15 @@ public ObjectWriter withSchema(FormatSchema schema) {
457442
*/
458443
public ObjectWriter forType(JavaType rootType)
459444
{
460-
JsonSerializer<Object> rootSer;
445+
Prefetch pf;
461446
if (rootType == null || rootType.hasRawClass(Object.class)) {
462-
rootType = null;
463-
rootSer = null;
447+
pf = Prefetch.empty;
464448
} else {
465449
// 15-Mar-2013, tatu: Important! Indicate that static typing is needed:
466450
rootType = rootType.withStaticTyping();
467-
rootSer = _prefetchRootSerializer(_config, rootType);
451+
pf = _prefetchRootSerializer(_config, rootType);
468452
}
469-
return _new(rootType, rootSer, _generatorSettings);
453+
return (pf == _prefetch) ? this : _new(_generatorSettings, pf);
470454
}
471455

472456
/**
@@ -553,7 +537,7 @@ public ObjectWriter with(CharacterEscapes escapes) {
553537
if (genSet == _generatorSettings) {
554538
return this;
555539
}
556-
return _new(_rootType, _rootSerializer, genSet);
540+
return _new(genSet, _prefetch);
557541
}
558542

559543
/**
@@ -806,7 +790,7 @@ public TypeFactory getTypeFactory() {
806790
* @since 2.2
807791
*/
808792
public boolean hasPrefetchedSerializer() {
809-
return _rootSerializer != null;
793+
return _prefetch.hasSerializer();
810794
}
811795

812796
/**
@@ -834,10 +818,13 @@ public void writeValue(JsonGenerator gen, Object value)
834818
&& (value instanceof Closeable)) {
835819
_writeCloseableValue(gen, value, _config);
836820
} else {
837-
if (_rootType == null) {
838-
_serializerProvider(_config).serializeValue(gen, value);
821+
if (_prefetch.valueSerializer != null) {
822+
_serializerProvider(_config).serializeValue(gen, value, _prefetch.rootType,
823+
_prefetch.valueSerializer);
824+
} else if (_prefetch.typeSerializer != null) {
825+
_serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.typeSerializer);
839826
} else {
840-
_serializerProvider(_config).serializeValue(gen, value, _rootType, _rootSerializer);
827+
_serializerProvider(_config).serializeValue(gen, value);
841828
}
842829
if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
843830
gen.flush();
@@ -1032,10 +1019,13 @@ protected final void _configAndWriteValue(JsonGenerator gen, Object value) throw
10321019
}
10331020
boolean closed = false;
10341021
try {
1035-
if (_rootType == null) {
1036-
_serializerProvider(_config).serializeValue(gen, value);
1022+
if (_prefetch.valueSerializer != null) {
1023+
_serializerProvider(_config).serializeValue(gen, value, _prefetch.rootType,
1024+
_prefetch.valueSerializer);
1025+
} else if (_prefetch.typeSerializer != null) {
1026+
_serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.typeSerializer);
10371027
} else {
1038-
_serializerProvider(_config).serializeValue(gen, value, _rootType, _rootSerializer);
1028+
_serializerProvider(_config).serializeValue(gen, value);
10391029
}
10401030
closed = true;
10411031
gen.close();
@@ -1064,10 +1054,13 @@ private final void _writeCloseable(JsonGenerator gen, Object value, Serializatio
10641054
{
10651055
Closeable toClose = (Closeable) value;
10661056
try {
1067-
if (_rootType == null) {
1068-
_serializerProvider(cfg).serializeValue(gen, value);
1057+
if (_prefetch.valueSerializer != null) {
1058+
_serializerProvider(cfg).serializeValue(gen, value, _prefetch.rootType,
1059+
_prefetch.valueSerializer);
1060+
} else if (_prefetch.typeSerializer != null) {
1061+
_serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.typeSerializer);
10691062
} else {
1070-
_serializerProvider(cfg).serializeValue(gen, value, _rootType, _rootSerializer);
1063+
_serializerProvider(cfg).serializeValue(gen, value);
10711064
}
10721065
JsonGenerator tmpGen = gen;
10731066
gen = null;
@@ -1105,10 +1098,13 @@ private final void _writeCloseableValue(JsonGenerator gen, Object value, Seriali
11051098
{
11061099
Closeable toClose = (Closeable) value;
11071100
try {
1108-
if (_rootType == null) {
1109-
_serializerProvider(cfg).serializeValue(gen, value);
1101+
if (_prefetch.valueSerializer != null) {
1102+
_serializerProvider(cfg).serializeValue(gen, value, _prefetch.rootType,
1103+
_prefetch.valueSerializer);
1104+
} else if (_prefetch.typeSerializer != null) {
1105+
_serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.typeSerializer);
11101106
} else {
1111-
_serializerProvider(cfg).serializeValue(gen, value, _rootType, _rootSerializer);
1107+
_serializerProvider(cfg).serializeValue(gen, value);
11121108
}
11131109
if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
11141110
gen.flush();
@@ -1130,18 +1126,23 @@ private final void _writeCloseableValue(JsonGenerator gen, Object value, Seriali
11301126
* by configuration. Method also is NOT to throw an exception if
11311127
* access fails.
11321128
*/
1133-
protected JsonSerializer<Object> _prefetchRootSerializer(
1134-
SerializationConfig config, JavaType valueType)
1129+
protected Prefetch _prefetchRootSerializer(SerializationConfig config, JavaType valueType)
11351130
{
1136-
if (valueType == null || !_config.isEnabled(SerializationFeature.EAGER_SERIALIZER_FETCH)) {
1137-
return null;
1138-
}
1139-
try {
1140-
return _serializerProvider(config).findTypedValueSerializer(valueType, true, null);
1141-
} catch (JsonProcessingException e) {
1142-
// need to swallow?
1143-
return null;
1131+
if (valueType != null && _config.isEnabled(SerializationFeature.EAGER_SERIALIZER_FETCH)) {
1132+
try {
1133+
TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, valueType);
1134+
// Polymorphic type? If so, can only do partial resolution
1135+
if (typeSer != null) {
1136+
return Prefetch.construct(valueType, typeSer);
1137+
}
1138+
JsonSerializer<Object> ser = _serializerProvider(config).findValueSerializer(valueType, null);
1139+
return Prefetch.construct(valueType, ser);
1140+
} catch (JsonProcessingException e) {
1141+
// need to swallow?
1142+
;
1143+
}
11441144
}
1145+
return Prefetch.empty;
11451146
}
11461147

11471148
/**
@@ -1259,4 +1260,64 @@ public GeneratorSettings with(CharacterEscapes esc) {
12591260
: new GeneratorSettings(prettyPrinter, schema, esc);
12601261
}
12611262
}
1263+
1264+
/**
1265+
* As a minor optimization, we will make an effort to pre-fetch a serializer,
1266+
* or at least relevant <code>TypeSerializer</code>, if given enough
1267+
* information.
1268+
*
1269+
* @since 2.5
1270+
*/
1271+
public final static class Prefetch
1272+
implements java.io.Serializable
1273+
{
1274+
private static final long serialVersionUID = 1L;
1275+
1276+
public final static Prefetch empty = new Prefetch(null, null, null);
1277+
1278+
/**
1279+
* Specified root serialization type to use; can be same
1280+
* as runtime type, but usually one of its super types
1281+
*/
1282+
public final JavaType rootType;
1283+
1284+
/**
1285+
* We may pre-fetch serializer if {@link #rootType}
1286+
* is known, and if so, reuse it afterwards.
1287+
* This allows avoiding further serializer lookups and increases
1288+
* performance a bit on cases where readers are reused.
1289+
*/
1290+
public final JsonSerializer<Object> valueSerializer;
1291+
1292+
/**
1293+
* When dealing with polymorphic types, we can not pre-fetch
1294+
* serializer, but we can pre-fetch {@link TypeSerializer}.
1295+
*/
1296+
public final TypeSerializer typeSerializer;
1297+
1298+
private Prefetch(JavaType type, JsonSerializer<Object> ser, TypeSerializer typeSer)
1299+
{
1300+
rootType = type;
1301+
valueSerializer = ser;
1302+
typeSerializer = typeSer;
1303+
}
1304+
1305+
public static Prefetch construct(JavaType type, JsonSerializer<Object> ser) {
1306+
if (type == null && ser == null) {
1307+
return empty;
1308+
}
1309+
return new Prefetch(type, ser, null);
1310+
}
1311+
1312+
public static Prefetch construct(JavaType type, TypeSerializer typeSer) {
1313+
if (type == null && typeSer == null) {
1314+
return empty;
1315+
}
1316+
return new Prefetch(type, null, typeSer);
1317+
}
1318+
1319+
public boolean hasSerializer() {
1320+
return (valueSerializer != null) || (typeSerializer != null);
1321+
}
1322+
}
12621323
}

0 commit comments

Comments
 (0)