Skip to content

Commit

Permalink
Complete #655 implementation (add ObjectWriter.writeValues())
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Dec 17, 2014
1 parent a199cbd commit 5ee6591
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 88 deletions.
1 change: 1 addition & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Project: jackson-databind
(using @JsonAppend, VirtualBeanPropertyWriter)
#647: Deserialization fails when @JsonUnwrapped property contains an object with same property name
(reported by Konstantin L)
#655: Add `ObjectWriter.writeValues()` for writing value sequences
- Allow use of `Shape.ARRAY` for Enums, as an alias to 'use index'
- Start using `JsonGenerator.writeStartArray(int)` to help data formats
that benefit from knowing number of elements in arrays (and would otherwise
Expand Down
193 changes: 127 additions & 66 deletions src/main/java/com/fasterxml/jackson/databind/ObjectWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.fasterxml.jackson.core.util.*;
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.type.TypeFactory;

Expand Down Expand Up @@ -62,29 +63,23 @@ public class ObjectWriter
*/

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

/**
* We may pre-fetch serializer if {@link #_rootType}
* is known, and if so, reuse it afterwards.
* This allows avoiding further serializer lookups and increases
* performance a bit on cases where readers are reused.
*
* @since 2.1
*/
protected final JsonSerializer<Object> _rootSerializer;

/**
* Container for settings that need to be passed to {@link JsonGenerator}
* constructed for serializing values.
*
* @since 2.5
*/
protected final GeneratorSettings _generatorSettings;

protected final Prefetch _prefetch;
/*
/**********************************************************
/* Life-cycle, constructors
Expand All @@ -106,11 +101,10 @@ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,

// 29-Apr-2014, tatu: There is no "untyped serializer", so:
if (rootType == null || rootType.hasRawClass(Object.class)) {
_rootType = null;
_rootSerializer = null;
_prefetch = Prefetch.empty;
} else {
_rootType = rootType.withStaticTyping();
_rootSerializer = _prefetchRootSerializer(config, _rootType);
rootType = rootType.withStaticTyping();
_prefetch = _prefetchRootSerializer(config, rootType);
}
}

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

_rootType = null;
_rootSerializer = null;
_prefetch = Prefetch.empty;
_generatorSettings = GeneratorSettings.empty;
}

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

_rootType = null;
_rootSerializer = null;
_prefetch = Prefetch.empty;
_generatorSettings = (s == null) ? GeneratorSettings.empty
: new GeneratorSettings(null, s, null);
}
Expand All @@ -151,18 +143,16 @@ protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
* Copy constructor used for building variations.
*/
protected ObjectWriter(ObjectWriter base, SerializationConfig config,
JavaType rootType, JsonSerializer<Object> rootSer,
GeneratorSettings genSettings)
GeneratorSettings genSettings, Prefetch prefetch)
{
_config = config;

_serializerProvider = base._serializerProvider;
_serializerFactory = base._serializerFactory;
_generatorFactory = base._generatorFactory;

_rootType = rootType;
_rootSerializer = rootSer;
_generatorSettings = genSettings;
_prefetch = prefetch;
}

/**
Expand All @@ -176,9 +166,7 @@ protected ObjectWriter(ObjectWriter base, SerializationConfig config)
_serializerFactory = base._serializerFactory;
_generatorFactory = base._generatorFactory;
_generatorSettings = base._generatorSettings;

_rootType = base._rootType;
_rootSerializer = base._rootSerializer;
_prefetch = base._prefetch;
}

/**
Expand All @@ -194,9 +182,7 @@ protected ObjectWriter(ObjectWriter base, JsonFactory f)
_serializerFactory = base._serializerFactory;
_generatorFactory = base._generatorFactory;
_generatorSettings = base._generatorSettings;

_rootType = base._rootType;
_rootSerializer = base._rootSerializer;
_prefetch = base._prefetch;
}

/**
Expand Down Expand Up @@ -241,9 +227,8 @@ protected ObjectWriter _new(ObjectWriter base, SerializationConfig config) {
*
* @since 2.5
*/
protected ObjectWriter _new(JavaType rootType, JsonSerializer<Object> rootSer,
GeneratorSettings genSettings) {
return new ObjectWriter(this, _config, rootType, rootSer, genSettings);
protected ObjectWriter _new(GeneratorSettings genSettings, Prefetch prefetch) {
return new ObjectWriter(this, _config, genSettings, prefetch);
}

/**
Expand All @@ -258,7 +243,7 @@ protected SequenceWriter _newSequenceWriter(boolean wrapInArray,
throws IOException
{
return new SequenceWriter(_serializerProvider(_config),
_configureGenerator(gen), managedInput, _rootType, _rootSerializer)
_configureGenerator(gen), managedInput, _prefetch)
.init(wrapInArray);
}

Expand Down Expand Up @@ -405,7 +390,7 @@ public ObjectWriter with(PrettyPrinter pp) {
if (genSet == _generatorSettings) {
return this;
}
return _new(_rootType, _rootSerializer, genSet);
return _new(genSet, _prefetch);
}

/**
Expand Down Expand Up @@ -434,7 +419,7 @@ public ObjectWriter with(FormatSchema schema) {
return this;
}
_verifySchemaType(schema);
return _new(_rootType, _rootSerializer, genSet);
return _new(genSet, _prefetch);
}

/**
Expand All @@ -457,16 +442,15 @@ public ObjectWriter withSchema(FormatSchema schema) {
*/
public ObjectWriter forType(JavaType rootType)
{
JsonSerializer<Object> rootSer;
Prefetch pf;
if (rootType == null || rootType.hasRawClass(Object.class)) {
rootType = null;
rootSer = null;
pf = Prefetch.empty;
} else {
// 15-Mar-2013, tatu: Important! Indicate that static typing is needed:
rootType = rootType.withStaticTyping();
rootSer = _prefetchRootSerializer(_config, rootType);
pf = _prefetchRootSerializer(_config, rootType);
}
return _new(rootType, rootSer, _generatorSettings);
return (pf == _prefetch) ? this : _new(_generatorSettings, pf);
}

/**
Expand Down Expand Up @@ -553,7 +537,7 @@ public ObjectWriter with(CharacterEscapes escapes) {
if (genSet == _generatorSettings) {
return this;
}
return _new(_rootType, _rootSerializer, genSet);
return _new(genSet, _prefetch);
}

/**
Expand Down Expand Up @@ -806,7 +790,7 @@ public TypeFactory getTypeFactory() {
* @since 2.2
*/
public boolean hasPrefetchedSerializer() {
return _rootSerializer != null;
return _prefetch.hasSerializer();
}

/**
Expand Down Expand Up @@ -834,10 +818,13 @@ public void writeValue(JsonGenerator gen, Object value)
&& (value instanceof Closeable)) {
_writeCloseableValue(gen, value, _config);
} else {
if (_rootType == null) {
_serializerProvider(_config).serializeValue(gen, value);
if (_prefetch.valueSerializer != null) {
_serializerProvider(_config).serializeValue(gen, value, _prefetch.rootType,
_prefetch.valueSerializer);
} else if (_prefetch.typeSerializer != null) {
_serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.typeSerializer);
} else {
_serializerProvider(_config).serializeValue(gen, value, _rootType, _rootSerializer);
_serializerProvider(_config).serializeValue(gen, value);
}
if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
gen.flush();
Expand Down Expand Up @@ -1032,10 +1019,13 @@ protected final void _configAndWriteValue(JsonGenerator gen, Object value) throw
}
boolean closed = false;
try {
if (_rootType == null) {
_serializerProvider(_config).serializeValue(gen, value);
if (_prefetch.valueSerializer != null) {
_serializerProvider(_config).serializeValue(gen, value, _prefetch.rootType,
_prefetch.valueSerializer);
} else if (_prefetch.typeSerializer != null) {
_serializerProvider(_config).serializePolymorphic(gen, value, _prefetch.typeSerializer);
} else {
_serializerProvider(_config).serializeValue(gen, value, _rootType, _rootSerializer);
_serializerProvider(_config).serializeValue(gen, value);
}
closed = true;
gen.close();
Expand Down Expand Up @@ -1064,10 +1054,13 @@ private final void _writeCloseable(JsonGenerator gen, Object value, Serializatio
{
Closeable toClose = (Closeable) value;
try {
if (_rootType == null) {
_serializerProvider(cfg).serializeValue(gen, value);
if (_prefetch.valueSerializer != null) {
_serializerProvider(cfg).serializeValue(gen, value, _prefetch.rootType,
_prefetch.valueSerializer);
} else if (_prefetch.typeSerializer != null) {
_serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.typeSerializer);
} else {
_serializerProvider(cfg).serializeValue(gen, value, _rootType, _rootSerializer);
_serializerProvider(cfg).serializeValue(gen, value);
}
JsonGenerator tmpGen = gen;
gen = null;
Expand Down Expand Up @@ -1105,10 +1098,13 @@ private final void _writeCloseableValue(JsonGenerator gen, Object value, Seriali
{
Closeable toClose = (Closeable) value;
try {
if (_rootType == null) {
_serializerProvider(cfg).serializeValue(gen, value);
if (_prefetch.valueSerializer != null) {
_serializerProvider(cfg).serializeValue(gen, value, _prefetch.rootType,
_prefetch.valueSerializer);
} else if (_prefetch.typeSerializer != null) {
_serializerProvider(cfg).serializePolymorphic(gen, value, _prefetch.typeSerializer);
} else {
_serializerProvider(cfg).serializeValue(gen, value, _rootType, _rootSerializer);
_serializerProvider(cfg).serializeValue(gen, value);
}
if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
gen.flush();
Expand All @@ -1130,18 +1126,23 @@ private final void _writeCloseableValue(JsonGenerator gen, Object value, Seriali
* by configuration. Method also is NOT to throw an exception if
* access fails.
*/
protected JsonSerializer<Object> _prefetchRootSerializer(
SerializationConfig config, JavaType valueType)
protected Prefetch _prefetchRootSerializer(SerializationConfig config, JavaType valueType)
{
if (valueType == null || !_config.isEnabled(SerializationFeature.EAGER_SERIALIZER_FETCH)) {
return null;
}
try {
return _serializerProvider(config).findTypedValueSerializer(valueType, true, null);
} catch (JsonProcessingException e) {
// need to swallow?
return null;
if (valueType != null && _config.isEnabled(SerializationFeature.EAGER_SERIALIZER_FETCH)) {
try {
TypeSerializer typeSer = _serializerFactory.createTypeSerializer(_config, valueType);
// Polymorphic type? If so, can only do partial resolution
if (typeSer != null) {
return Prefetch.construct(valueType, typeSer);
}
JsonSerializer<Object> ser = _serializerProvider(config).findValueSerializer(valueType, null);
return Prefetch.construct(valueType, ser);
} catch (JsonProcessingException e) {
// need to swallow?
;
}
}
return Prefetch.empty;
}

/**
Expand Down Expand Up @@ -1259,4 +1260,64 @@ public GeneratorSettings with(CharacterEscapes esc) {
: new GeneratorSettings(prettyPrinter, schema, esc);
}
}

/**
* As a minor optimization, we will make an effort to pre-fetch a serializer,
* or at least relevant <code>TypeSerializer</code>, if given enough
* information.
*
* @since 2.5
*/
public final static class Prefetch
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;

public final static Prefetch empty = new Prefetch(null, null, null);

/**
* Specified root serialization type to use; can be same
* as runtime type, but usually one of its super types
*/
public final JavaType rootType;

/**
* We may pre-fetch serializer if {@link #rootType}
* is known, and if so, reuse it afterwards.
* This allows avoiding further serializer lookups and increases
* performance a bit on cases where readers are reused.
*/
public final JsonSerializer<Object> valueSerializer;

/**
* When dealing with polymorphic types, we can not pre-fetch
* serializer, but we can pre-fetch {@link TypeSerializer}.
*/
public final TypeSerializer typeSerializer;

private Prefetch(JavaType type, JsonSerializer<Object> ser, TypeSerializer typeSer)
{
rootType = type;
valueSerializer = ser;
typeSerializer = typeSer;
}

public static Prefetch construct(JavaType type, JsonSerializer<Object> ser) {
if (type == null && ser == null) {
return empty;
}
return new Prefetch(type, ser, null);
}

public static Prefetch construct(JavaType type, TypeSerializer typeSer) {
if (type == null && typeSer == null) {
return empty;
}
return new Prefetch(type, null, typeSer);
}

public boolean hasSerializer() {
return (valueSerializer != null) || (typeSerializer != null);
}
}
}
Loading

0 comments on commit 5ee6591

Please sign in to comment.