Package com.fasterxml.jackson.databind

Source Code of com.fasterxml.jackson.databind.ObjectWriter

package com.fasterxml.jackson.databind;

import java.io.*;
import java.text.DateFormat;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.io.SegmentedStringWriter;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.core.util.ByteArrayBuilder;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.Instantiatable;
import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.ser.DefaultSerializerProvider;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.SerializerFactory;
import com.fasterxml.jackson.databind.type.TypeFactory;

/**
* Builder object that can be used for per-serialization configuration of
* serialization parameters, such as JSON View and root type to use.
* (and thus fully thread-safe with no external synchronization);
* new instances are constructed for different configurations.
* Instances are initially constructed by {@link ObjectMapper} and can be
* reused in completely thread-safe manner with no explicit synchronization
*/
public class ObjectWriter
    implements Versioned,
        java.io.Serializable // since 2.1
{
    private static final long serialVersionUID = 1; // since 2.5

    /**
     * We need to keep track of explicit disabling of pretty printing;
     * easiest to do by a token value.
     */
    protected final static PrettyPrinter NULL_PRETTY_PRINTER = new MinimalPrettyPrinter();
   
    /*
    /**********************************************************
    /* Immutable configuration from ObjectMapper
    /**********************************************************
     */

    /**
     * General serialization configuration settings
     */
    protected final SerializationConfig _config;
  
    protected final DefaultSerializerProvider _serializerProvider;

    protected final SerializerFactory _serializerFactory;

    /**
     * Factory used for constructing {@link JsonGenerator}s
     */
    protected final JsonFactory _generatorFactory;

    /*
    /**********************************************************
    /* Configuration that can be changed via mutant factories
    /**********************************************************
     */

    /**
     * Specified root serialization type to use; can be same
     * as runtime type, but usually one of its super types
     */
    protected 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.
     *
     * @since 2.1
     */
    protected final JsonSerializer<Object> _rootSerializer;
   
    /**
     * To allow for dynamic enabling/disabling of pretty printing,
     * pretty printer can be optionally configured for writer
     * as well
     */
    protected final PrettyPrinter _prettyPrinter;
   
    /**
     * When using data format that uses a schema, schema is passed
     * to generator.
     */
    protected final FormatSchema _schema;
   
    /**
     * Caller may want to specify character escaping details, either as
     * defaults, or on call-by-call basis.
     *
     * @since 2.3
     */
    protected final CharacterEscapes _characterEscapes;

    /*
    /**********************************************************
    /* Life-cycle, constructors
    /**********************************************************
     */

    /**
     * Constructor used by {@link ObjectMapper} for initial instantiation
     */
    protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
            JavaType rootType, PrettyPrinter pp)
    {
        _config = config;
        _serializerProvider = mapper._serializerProvider;
        _serializerFactory = mapper._serializerFactory;
        _generatorFactory = mapper._jsonFactory;
        _prettyPrinter = pp;
        _schema = null;
        _characterEscapes = null;

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

    /**
     * Alternative constructor for initial instantiation by {@link ObjectMapper}
     */
    protected ObjectWriter(ObjectMapper mapper, SerializationConfig config)
    {
        _config = config;
        _serializerProvider = mapper._serializerProvider;
        _serializerFactory = mapper._serializerFactory;
        _generatorFactory = mapper._jsonFactory;

        _rootType = null;
        _rootSerializer = null;
        _prettyPrinter = null;
        _schema = null;
        _characterEscapes = null;
    }

    /**
     * Alternative constructor for initial instantiation by {@link ObjectMapper}
     */
    protected ObjectWriter(ObjectMapper mapper, SerializationConfig config,
            FormatSchema s)
    {
        _config = config;

        _serializerProvider = mapper._serializerProvider;
        _serializerFactory = mapper._serializerFactory;
        _generatorFactory = mapper._jsonFactory;

        _rootType = null;
        _rootSerializer = null;
        _prettyPrinter = null;
        _schema = s;
        _characterEscapes = null;
    }
   
    /**
     * Copy constructor used for building variations.
     */
    protected ObjectWriter(ObjectWriter base, SerializationConfig config,
            JavaType rootType, JsonSerializer<Object> rootSer,
            PrettyPrinter pp, FormatSchema s, CharacterEscapes escapes)
    {
        _config = config;

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

        _rootType = rootType;
        _rootSerializer = rootSer;
        _prettyPrinter = pp;
        _schema = s;
        _characterEscapes = escapes;
    }

    /**
     * Copy constructor used for building variations.
     */
    protected ObjectWriter(ObjectWriter base, SerializationConfig config)
    {
        _config = config;

        _serializerProvider = base._serializerProvider;
        _serializerFactory = base._serializerFactory;
        _generatorFactory = base._generatorFactory;
        _schema = base._schema;
        _characterEscapes = base._characterEscapes;

        _rootType = base._rootType;
        _rootSerializer = base._rootSerializer;
        _prettyPrinter = base._prettyPrinter;
    }

    /**
     * @since 2.3
     */
    protected ObjectWriter(ObjectWriter base, JsonFactory f)
    {
        // may need to override ordering, based on data format capabilities
        _config = base._config
            .with(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, f.requiresPropertyOrdering());

        _serializerProvider = base._serializerProvider;
        _serializerFactory = base._serializerFactory;
        _generatorFactory = base._generatorFactory;
        _schema = base._schema;
        _characterEscapes = base._characterEscapes;

        _rootType = base._rootType;
        _rootSerializer = base._rootSerializer;
        _prettyPrinter = base._prettyPrinter;
    }
   
    /**
     * Method that will return version information stored in and read from jar
     * that contains this class.
     */
    @Override
    public Version version() {
        return com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION;
    }
   
    /*
    /**********************************************************
    /* Life-cycle, fluent factories for SerializationFeature
    /**********************************************************
     */

    /**
     * Method for constructing a new instance that is configured
     * with specified feature enabled.
     */
    public ObjectWriter with(SerializationFeature feature)  {
        SerializationConfig newConfig = _config.with(feature);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /**
     * Method for constructing a new instance that is configured
     * with specified features enabled.
     */
    public ObjectWriter with(SerializationFeature first, SerializationFeature... other) {
        SerializationConfig newConfig = _config.with(first, other);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }   

    /**
     * Method for constructing a new instance that is configured
     * with specified features enabled.
     */
    public ObjectWriter withFeatures(SerializationFeature... features) {
        SerializationConfig newConfig = _config.withFeatures(features);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }   
   
    /**
     * Method for constructing a new instance that is configured
     * with specified feature enabled.
     */
    public ObjectWriter without(SerializationFeature feature) {
        SerializationConfig newConfig = _config.without(feature);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }   

    /**
     * Method for constructing a new instance that is configured
     * with specified features enabled.
     */
    public ObjectWriter without(SerializationFeature first, SerializationFeature... other) {
        SerializationConfig newConfig = _config.without(first, other);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }   

    /**
     * Method for constructing a new instance that is configured
     * with specified features enabled.
     */
    public ObjectWriter withoutFeatures(SerializationFeature... features) {
        SerializationConfig newConfig = _config.withoutFeatures(features);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /*
    /**********************************************************
    /* Life-cycle, fluent factories for JsonGenerator.Feature
    /**********************************************************
     */

    /**
     * @since 2.5
     */
    public ObjectWriter with(JsonGenerator.Feature feature)  {
        SerializationConfig newConfig = _config.with(feature);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.5
     */
    public ObjectWriter withFeatures(JsonGenerator.Feature... features) {
        SerializationConfig newConfig = _config.withFeatures(features);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.5
     */
    public ObjectWriter without(JsonGenerator.Feature feature) {
        SerializationConfig newConfig = _config.without(feature);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.5
     */
    public ObjectWriter withoutFeatures(JsonGenerator.Feature... features) {
        SerializationConfig newConfig = _config.withoutFeatures(features);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /*
    /**********************************************************
    /* Life-cycle, fluent factories, other
    /**********************************************************
     */

    /**
     * Fluent factory method that will construct a new writer instance that will
     * use specified date format for serializing dates; or if null passed, one
     * that will serialize dates as numeric timestamps.
     *<p>
     * Note that the method does NOT change state of this reader, but
     * rather construct and returns a newly configured instance.
     */
    public ObjectWriter with(DateFormat df) {
        SerializationConfig newConfig = _config.with(df);
        return (newConfig == _config) ? this : new ObjectWriter(this, newConfig);
    }

    /**
     * Method that will construct a new instance that will use the default
     * pretty printer for serialization.
     */
    public ObjectWriter withDefaultPrettyPrinter() {
        return with(new DefaultPrettyPrinter());
    }

    /**
     * Method that will construct a new instance that uses specified
     * provider for resolving filter instances by id.
     */
    public ObjectWriter with(FilterProvider filterProvider) {
        return (filterProvider == _config.getFilterProvider()) ? this
                 : new ObjectWriter(this, _config.withFilters(filterProvider));
    }

    /**
     * Method that will construct a new instance that will use specified pretty
     * printer (or, if null, will not do any pretty-printing)
     */
    public ObjectWriter with(PrettyPrinter pp) {
        if (pp == _prettyPrinter) {
            return this;
        }
        // since null would mean "don't care", need to use placeholder to indicate "disable"
        if (pp == null) {
            pp = NULL_PRETTY_PRINTER;
        }
        return new ObjectWriter(this, _config, _rootType, _rootSerializer,
                pp, _schema, _characterEscapes);
    }

    /**
     * Method for constructing a new instance with configuration that
     * specifies what root name to use for "root element wrapping".
     * See {@link SerializationConfig#withRootName(String)} for details.
     *<p>
     * Note that method does NOT change state of this reader, but
     * rather construct and returns a newly configured instance.
     */
    public ObjectWriter withRootName(String rootName) {
        SerializationConfig newConfig = _config.withRootName(rootName);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    /**
     * Method that will construct a new instance that uses specific format schema
     * for serialization.
     *<p>
     * Note that method does NOT change state of this reader, but
     * rather construct and returns a newly configured instance.
     */
   
    public ObjectWriter withSchema(FormatSchema schema) {
        if (_schema == schema) {
            return this;
        }
        _verifySchemaType(schema);
        return new ObjectWriter(this, _config, _rootType, _rootSerializer,
                _prettyPrinter, schema, _characterEscapes);
    }

    /**
     * Method that will construct a new instance that uses specific type
     * as the root type for serialization, instead of runtime dynamic
     * type of the root object itself.
     *<p>
     * Note that method does NOT change state of this reader, but
     * rather construct and returns a newly configured instance.
     */
    public ObjectWriter withType(JavaType rootType)
    {
        JsonSerializer<Object> rootSer;
        if (rootType == null || rootType.hasRawClass(Object.class)) {
            rootType = null;
            rootSer = null;
        } else {
            // 15-Mar-2013, tatu: Important! Indicate that static typing is needed:
            rootType = rootType.withStaticTyping();
            rootSer = _prefetchRootSerializer(_config, rootType);
        }
        return new ObjectWriter(this, _config, rootType, rootSer,
                _prettyPrinter, _schema, _characterEscapes);
    }   

    /**
     * Method that will construct a new instance that uses specific type
     * as the root type for serialization, instead of runtime dynamic
     * type of the root object itself.
     */
    public ObjectWriter withType(Class<?> rootType) {
        if (rootType == Object.class) {
            return withType((JavaType) null);
        }
        return withType(_config.constructType(rootType));
    }

    public ObjectWriter withType(TypeReference<?> rootType) {
        return withType(_config.getTypeFactory().constructType(rootType.getType()));
    }

    /**
     * Method that will construct a new instance that uses specified
     * serialization view for serialization (with null basically disables
     * view processing)
     *<p>
     * Note that the method does NOT change state of this reader, but
     * rather construct and returns a newly configured instance.
     */
    public ObjectWriter withView(Class<?> view) {
        SerializationConfig newConfig = _config.withView(view);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }   

    public ObjectWriter with(Locale l) {
        SerializationConfig newConfig = _config.with(l);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    public ObjectWriter with(TimeZone tz) {
        SerializationConfig newConfig = _config.with(tz);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    /**
     * Method that will construct a new instance that uses specified default
     * {@link Base64Variant} for base64 encoding
     *
     * @since 2.1
     */
    public ObjectWriter with(Base64Variant b64variant) {
        SerializationConfig newConfig = _config.with(b64variant);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.3
     */
    public ObjectWriter with(CharacterEscapes escapes) {
        if (_characterEscapes == escapes) {
            return this;
        }
        return new ObjectWriter(this, _config, _rootType, _rootSerializer,
                _prettyPrinter, _schema, escapes);
    }

    /**
     * @since 2.3
     */
    public ObjectWriter with(JsonFactory f) {
        return (f == _generatorFactory) ? this : new ObjectWriter(this, f);
    }   

    /**
     * @since 2.3
     */
    public ObjectWriter with(ContextAttributes attrs) {
        SerializationConfig newConfig = _config.with(attrs);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.3
     */
    public ObjectWriter withAttributes(Map<Object,Object> attrs) {
        SerializationConfig newConfig = _config.withAttributes(attrs);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.3
     */
    public ObjectWriter withAttribute(Object key, Object value) {
        SerializationConfig newConfig = _config.withAttribute(key, value);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }

    /**
     * @since 2.3
     */
    public ObjectWriter withoutAttribute(Object key) {
        SerializationConfig newConfig = _config.withoutAttribute(key);
        return (newConfig == _config) ? this new ObjectWriter(this, newConfig);
    }
   
    /*
    /**********************************************************
    /* Simple accessors
    /**********************************************************
     */

    public boolean isEnabled(SerializationFeature f) {
        return _config.isEnabled(f);
    }

    public boolean isEnabled(MapperFeature f) {
        return _config.isEnabled(f);
    }

    public boolean isEnabled(JsonParser.Feature f) {
        return _generatorFactory.isEnabled(f);
    }

    /**
     * @since 2.2
     */
    public SerializationConfig getConfig() {
        return _config;
    }

    /**
     * @deprecated Since 2.2, use {@link #getFactory} instead.
     */
    @Deprecated
    public JsonFactory getJsonFactory() {
        return _generatorFactory;
    }

    /**
     * @since 2.2
     */
    public JsonFactory getFactory() {
        return _generatorFactory;
    }
   
    public TypeFactory getTypeFactory() {
        return _config.getTypeFactory();
    }

    /**
     * Diagnostics method that can be called to check whether this writer
     * has pre-fetched serializer to use: pre-fetching improves performance
     * when writer instances are reused as it avoids a per-call serializer
     * lookup.
     *
     * @since 2.2
     */
    public boolean hasPrefetchedSerializer() {
        return _rootSerializer != null;
    }

    /**
     * @since 2.3
     */
    public ContextAttributes getAttributes() {
        return _config.getAttributes();
    }
   
    /*
    /**********************************************************
    /* Serialization methods; ones from ObjectCodec first
    /**********************************************************
     */

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, using provided {@link JsonGenerator}.
     */
    public void writeValue(JsonGenerator jgen, Object value)
        throws IOException, JsonGenerationException, JsonMappingException
    {
        // 10-Aug-2012, tatu: As per [Issue#12], may need to force PrettyPrinter settings, so:
        _configureJsonGenerator(jgen);
        if (_config.isEnabled(SerializationFeature.CLOSE_CLOSEABLE)
                && (value instanceof Closeable)) {
            _writeCloseableValue(jgen, value, _config);
        } else {
            if (_rootType == null) {
                _serializerProvider(_config).serializeValue(jgen, value);
            } else {
                _serializerProvider(_config).serializeValue(jgen, value, _rootType, _rootSerializer);
            }
            if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
                jgen.flush();
            }
        }
    }
   
    /*
    /**********************************************************
    /* Serialization methods, others
    /**********************************************************
     */

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, written to File provided.
     */
    public void writeValue(File resultFile, Object value)
        throws IOException, JsonGenerationException, JsonMappingException
    {
        _configAndWriteValue(_generatorFactory.createGenerator(resultFile, JsonEncoding.UTF8), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, using output stream provided (using encoding
     * {@link JsonEncoding#UTF8}).
     *<p>
     * Note: method does not close the underlying stream explicitly
     * here; however, {@link JsonFactory} this mapper uses may choose
     * to close the stream depending on its settings (by default,
     * it will try to close it when {@link JsonGenerator} we construct
     * is closed).
     */
    public void writeValue(OutputStream out, Object value)
        throws IOException, JsonGenerationException, JsonMappingException
    {
        _configAndWriteValue(_generatorFactory.createGenerator(out, JsonEncoding.UTF8), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * JSON output, using Writer provided.
     *<p>
     * Note: method does not close the underlying stream explicitly
     * here; however, {@link JsonFactory} this mapper uses may choose
     * to close the stream depending on its settings (by default,
     * it will try to close it when {@link JsonGenerator} we construct
     * is closed).
     */
    public void writeValue(Writer w, Object value)
        throws IOException, JsonGenerationException, JsonMappingException
    {
        _configAndWriteValue(_generatorFactory.createGenerator(w), value);
    }

    /**
     * Method that can be used to serialize any Java value as
     * a String. Functionally equivalent to calling
     * {@link #writeValue(Writer,Object)} with {@link java.io.StringWriter}
     * and constructing String, but more efficient.
     *<p>
     * Note: prior to version 2.1, throws clause included {@link IOException}; 2.1 removed it.
     */
    @SuppressWarnings("resource")
    public String writeValueAsString(Object value)
        throws JsonProcessingException
    {       
        // alas, we have to pull the recycler directly here...
        SegmentedStringWriter sw = new SegmentedStringWriter(_generatorFactory._getBufferRecycler());
        try {
            _configAndWriteValue(_generatorFactory.createGenerator(sw), value);
        } catch (JsonProcessingException e) { // to support [JACKSON-758]
            throw e;
        } catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
            throw JsonMappingException.fromUnexpectedIOE(e);
        }
        return sw.getAndClear();
    }
   
    /**
     * Method that can be used to serialize any Java value as
     * a byte array. Functionally equivalent to calling
     * {@link #writeValue(Writer,Object)} with {@link java.io.ByteArrayOutputStream}
     * and getting bytes, but more efficient.
     * Encoding used will be UTF-8.
     *<p>
     * Note: prior to version 2.1, throws clause included {@link IOException}; 2.1 removed it.
     */
    @SuppressWarnings("resource")
    public byte[] writeValueAsBytes(Object value)
        throws JsonProcessingException
    {
        ByteArrayBuilder bb = new ByteArrayBuilder(_generatorFactory._getBufferRecycler());
        try {
            _configAndWriteValue(_generatorFactory.createGenerator(bb, JsonEncoding.UTF8), value);
        } catch (JsonProcessingException e) { // to support [JACKSON-758]
            throw e;
        } catch (IOException e) { // shouldn't really happen, but is declared as possibility so:
            throw JsonMappingException.fromUnexpectedIOE(e);
        }
        byte[] result = bb.toByteArray();
        bb.release();
        return result;
    }

    /*
    /**********************************************************
    /* Other public methods
    /**********************************************************
     */

    /**
     * Method for visiting type hierarchy for given type, using specified visitor.
     * Visitation uses <code>Serializer</code> hierarchy and related properties
     *<p>
     * This method can be used for things like
     * generating <a href="http://json-schema.org/">Json Schema</a>
     * instance for specified type.
     *
     * @param type Type to generate schema for (possibly with generic signature)
     *
     * @since 2.2
     */
    public void acceptJsonFormatVisitor(JavaType type, JsonFormatVisitorWrapper visitor)
        throws JsonMappingException
    {
        if (type == null) {
            throw new IllegalArgumentException("type must be provided");
        }
        _serializerProvider(_config).acceptJsonFormatVisitor(type, visitor);
    }
   
    public boolean canSerialize(Class<?> type) {
        return _serializerProvider(_config).hasSerializerFor(type, null);
    }

    /**
     * Method for checking whether instances of given type can be serialized,
     * and optionally why (as per {@link Throwable} returned).
     *
     * @since 2.3
     */
    public boolean canSerialize(Class<?> type, AtomicReference<Throwable> cause) {
        return _serializerProvider(_config).hasSerializerFor(type, cause);
    }
   
    /*
    /**********************************************************
    /* Overridable helper methods
    /**********************************************************
     */
   
    /**
     * Overridable helper method used for constructing
     * {@link SerializerProvider} to use for serialization.
     */
    protected DefaultSerializerProvider _serializerProvider(SerializationConfig config) {
        return _serializerProvider.createInstance(config, _serializerFactory);
    }
   
    /*
    /**********************************************************
    /* Internal methods
    /**********************************************************
     */

    /**
     * @since 2.2
     */
    protected void _verifySchemaType(FormatSchema schema)
    {
        if (schema != null) {
            if (!_generatorFactory.canUseSchema(schema)) {
                    throw new IllegalArgumentException("Can not use FormatSchema of type "+schema.getClass().getName()
                            +" for format "+_generatorFactory.getFormatName());
            }
        }
    }

    /**
     * Method called to configure the generator as necessary and then
     * call write functionality
     */
    protected final void _configAndWriteValue(JsonGenerator jgen, Object value) throws IOException
    {
        _configureJsonGenerator(jgen);
        // [JACKSON-282]: consider Closeable
        if (_config.isEnabled(SerializationFeature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) {
            _writeCloseable(jgen, value, _config);
            return;
        }
        boolean closed = false;
        try {
            if (_rootType == null) {
                _serializerProvider(_config).serializeValue(jgen, value);
            } else {
                _serializerProvider(_config).serializeValue(jgen, value, _rootType, _rootSerializer);
            }
            closed = true;
            jgen.close();
        } finally {
            /* won't try to close twice; also, must catch exception (so it
             * will not mask exception that is pending)
             */
            if (!closed) {
                /* 04-Mar-2014, tatu: But! Let's try to prevent auto-closing of
                 *    structures, which typically causes more damage.
                 */
                jgen.disable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT);
                try {
                    jgen.close();
                } catch (IOException ioe) { }
            }
        }
    }

    /**
     * Helper method used when value to serialize is {@link Closeable} and its <code>close()</code>
     * method is to be called right after serialization has been called
     */
    private final void _writeCloseable(JsonGenerator jgen, Object value, SerializationConfig cfg)
        throws IOException
    {
        Closeable toClose = (Closeable) value;
        try {
            if (_rootType == null) {
                _serializerProvider(cfg).serializeValue(jgen, value);
            } else {
                _serializerProvider(cfg).serializeValue(jgen, value, _rootType, _rootSerializer);
            }
            JsonGenerator tmpJgen = jgen;
            jgen = null;
            tmpJgen.close();
            Closeable tmpToClose = toClose;
            toClose = null;
            tmpToClose.close();
        } finally {
            /* Need to close both generator and value, as long as they haven't yet
             * been closed
             */
            if (jgen != null) {
                /* 04-Mar-2014, tatu: But! Let's try to prevent auto-closing of
                 *    structures, which typically causes more damage.
                 */
                jgen.disable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT);
                try {
                    jgen.close();
                } catch (IOException ioe) { }
            }
            if (toClose != null) {
                try {
                    toClose.close();
                } catch (IOException ioe) { }
            }
        }
    }
   
    /**
     * Helper method used when value to serialize is {@link Closeable} and its <code>close()</code>
     * method is to be called right after serialization has been called
     */
    private final void _writeCloseableValue(JsonGenerator jgen, Object value, SerializationConfig cfg)
        throws IOException
    {
        Closeable toClose = (Closeable) value;
        try {
            if (_rootType == null) {
                _serializerProvider(cfg).serializeValue(jgen, value);
            } else {
                _serializerProvider(cfg).serializeValue(jgen, value, _rootType, _rootSerializer);
            }
            if (_config.isEnabled(SerializationFeature.FLUSH_AFTER_WRITE_VALUE)) {
                jgen.flush();
            }
            Closeable tmpToClose = toClose;
            toClose = null;
            tmpToClose.close();
        } finally {
            if (toClose != null) {
                try {
                    toClose.close();
                } catch (IOException ioe) { }
            }
        }
    }

    /**
     * Method called to locate (root) serializer ahead of time, if permitted
     * by configuration. Method also is NOT to throw an exception if
     * access fails.
     */
    protected JsonSerializer<Object> _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;
        }
    }
   
    /**
     * Helper method called to set or override settings of passed-in
     * {@link JsonGenerator}
     *
     * @since 2.1
     */
    protected void _configureJsonGenerator(JsonGenerator gen)
    {
        if (_prettyPrinter != null) {
            PrettyPrinter pp = _prettyPrinter;
            if (pp == NULL_PRETTY_PRINTER) {
                gen.setPrettyPrinter(null);
            } else {
                /* [JACKSON-851]: Better take care of stateful PrettyPrinters...
                 *   like the DefaultPrettyPrinter.
                 */
                if (pp instanceof Instantiatable<?>) {
                    pp = (PrettyPrinter) ((Instantiatable<?>) pp).createInstance();
                }
                gen.setPrettyPrinter(pp);
            }
        } else if (_config.isEnabled(SerializationFeature.INDENT_OUTPUT)) {
            gen.useDefaultPrettyPrinter();
        }
        if (_characterEscapes != null) {
            gen.setCharacterEscapes(_characterEscapes);
        }
        // [JACKSON-520]: add support for pass-through schema:
        if (_schema != null) {
            gen.setSchema(_schema);
        }
        _config.initialize(gen); // since 2.5
    }
}
TOP

Related Classes of com.fasterxml.jackson.databind.ObjectWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.