Jackson Data Binding Source Code

Jackson is "the Java JSON library" or "the best JSON parser for Java". Or simply as "JSON for Java".

  • Jackson Data Binding module allows you to converts JSON to and from POJO (Plain Old Java Object) using property accessor or using annotations.
  • Jackson Databind Source Code files are provided in the source packge (jackson-databind-2.12.4-sources.jar). You can download it at Jackson Maven Website.

    You can also browse Jackson Databind Source Code below:

    ✍: FYIcenter.com

    com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java

    package com.fasterxml.jackson.databind.ser.std;
    
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Type;
    import java.util.LinkedHashSet;
    import java.util.Set;
    
    import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
    
    import com.fasterxml.jackson.core.*;
    import com.fasterxml.jackson.core.type.WritableTypeId;
    
    import com.fasterxml.jackson.databind.*;
    import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
    import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
    import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
    import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
    import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor;
    import com.fasterxml.jackson.databind.jsonschema.SchemaAware;
    import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
    import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
    import com.fasterxml.jackson.databind.ser.BeanSerializer;
    import com.fasterxml.jackson.databind.ser.ContextualSerializer;
    import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
    import com.fasterxml.jackson.databind.util.ClassUtil;
    
    /**
     * Serializer class that can serialize Object that have a
     * {@link com.fasterxml.jackson.annotation.JsonValue} annotation to
     * indicate that serialization should be done by calling the method
     * annotated, and serializing result it returns.
     *<p>
     * Implementation note: we will post-process resulting serializer
     * (much like what is done with {@link BeanSerializer})
     * to figure out actual serializers for final types.
     *  This must be done from {@link #createContextual} method, and NOT from constructor;
     * otherwise we could end up with an infinite loop.
     */
    @SuppressWarnings("serial")
    @JacksonStdImpl
    public class JsonValueSerializer
        extends StdSerializer<Object>
        implements ContextualSerializer, JsonFormatVisitable, SchemaAware
    {
        /**
         * @since 2.9
         */
        protected final AnnotatedMember _accessor;
    
        /**
         * @since 2.12
         */
        protected final TypeSerializer _valueTypeSerializer;
    
        protected final JsonSerializer<Object> _valueSerializer;
    
        protected final BeanProperty _property;
    
        /**
         * Declared type of the value accessed, as declared by accessor.
         *
         * @since 2.12
         */
        protected final JavaType _valueType;
    
        /**
         * This is a flag that is set in rare (?) cases where this serializer
         * is used for "natural" types (boolean, int, String, double); and where
         * we actually must force type information wrapping, even though
         * one would not normally be added.
         */
        protected final boolean _forceTypeInformation;
    
        /**
         * If value type cannot be statically determined, mapping from
         * runtime value types to serializers are cached in this object.
         *
         * @since 2.12
         */
        protected transient PropertySerializerMap _dynamicSerializers;
    
        /*
        /**********************************************************
        /* Life-cycle
        /**********************************************************
         */
    
        /**
         * @param ser Explicit serializer to use, if caller knows it (which
         *    occurs if and only if the "value method" was annotated with
         *    {@link com.fasterxml.jackson.databind.annotation.JsonSerialize#using}), otherwise
         *    null
         *
         * @since 2.12 added {@link TypeSerializer} since 2.11
         */
        @SuppressWarnings("unchecked")
        public JsonValueSerializer(AnnotatedMember accessor,
                TypeSerializer vts, JsonSerializer<?> ser)
        {
            super(accessor.getType());
            _accessor = accessor;
            _valueType = accessor.getType();
            _valueTypeSerializer = vts;
            _valueSerializer = (JsonSerializer<Object>) ser;
            _property = null;
            _forceTypeInformation = true; // gets reconsidered when we are contextualized
            _dynamicSerializers = PropertySerializerMap.emptyForProperties();
        }
    
        /**
         * @deprecated Since 2.12
         */
        @Deprecated
        public JsonValueSerializer(AnnotatedMember accessor, JsonSerializer<?> ser) {
            this(accessor, null, ser);
        }
    
        // @since 2.12
        @SuppressWarnings("unchecked")
        public JsonValueSerializer(JsonValueSerializer src, BeanProperty property,
                TypeSerializer vts, JsonSerializer<?> ser, boolean forceTypeInfo)
        {
            super(_notNullClass(src.handledType()));
            _accessor = src._accessor;
            _valueType = src._valueType;
            _valueTypeSerializer = vts;
            _valueSerializer = (JsonSerializer<Object>) ser;
            _property = property;
            _forceTypeInformation = forceTypeInfo;
            _dynamicSerializers = PropertySerializerMap.emptyForProperties();
        }
    
        @SuppressWarnings("unchecked")
        private final static Class<Object> _notNullClass(Class<?> cls) {
            return (cls == null) ? Object.class : (Class<Object>) cls;
        }
    
        protected JsonValueSerializer withResolved(BeanProperty property,
                TypeSerializer vts, JsonSerializer<?> ser, boolean forceTypeInfo)
        {
            if ((_property == property)
                    && (_valueTypeSerializer == vts) && (_valueSerializer == ser)
                    && (forceTypeInfo == _forceTypeInformation)) {
                return this;
            }
            return new JsonValueSerializer(this, property, vts, ser, forceTypeInfo);
        }
    
        /*
        /**********************************************************
        /* Overrides
        /**********************************************************
         */
    
        @Override // since 2.12
        public boolean isEmpty(SerializerProvider ctxt, Object bean)
        {
            // 31-Oct-2020, tatu: Should perhaps catch access issue here... ?
            Object referenced = _accessor.getValue(bean);
            if (referenced == null) {
                return true;
            }
            JsonSerializer<Object> ser = _valueSerializer;
            if (ser == null) {
                try {
                    ser = _findDynamicSerializer(ctxt, referenced.getClass());
                } catch (JsonMappingException e) {
                    throw new RuntimeJsonMappingException(e);
                }
            }
            return ser.isEmpty(ctxt, referenced);
        }
    
        /*
        /**********************************************************
        /* Post-processing
        /**********************************************************
         */
    
        /**
         * We can try to find the actual serializer for value, if we can
         * statically figure out what the result type must be.
         */
        @Override
        public JsonSerializer<?> createContextual(SerializerProvider ctxt,
                BeanProperty property)
            throws JsonMappingException
        {
            TypeSerializer typeSer = _valueTypeSerializer;
            if (typeSer != null) {
                typeSer = typeSer.forProperty(property);
            }
            JsonSerializer<?> ser = _valueSerializer;
            if (ser == null) {
                // Can only assign serializer statically if the declared type is final:
                // if not, we don't really know the actual type until we get the instance.
    
                // 10-Mar-2010, tatu: Except if static typing is to be used
                if (ctxt.isEnabled(MapperFeature.USE_STATIC_TYPING) || _valueType.isFinal()) {
                    /* 10-Mar-2010, tatu: Ideally we would actually separate out type
                     *   serializer from value serializer; but, alas, there's no access
                     *   to serializer factory at this point... 
                     */
                    // 05-Sep-2013, tatu: I _think_ this can be considered a primary property...
                    ser = ctxt.findPrimaryPropertySerializer(_valueType, property);
                    /* 09-Dec-2010, tatu: Turns out we must add special handling for
                     *   cases where "native" (aka "natural") type is being serialized,
                     *   using standard serializer
                     */
                    boolean forceTypeInformation = isNaturalTypeWithStdHandling(_valueType.getRawClass(), ser);
                    return withResolved(property, typeSer, ser, forceTypeInformation);
                }
                // [databind#2822]: better hold on to "property", regardless
                if (property != _property) {
                    return withResolved(property, typeSer, ser, _forceTypeInformation);
                }
            } else {
                // 05-Sep-2013, tatu: I _think_ this can be considered a primary property...
                ser = ctxt.handlePrimaryContextualization(ser, property);
                return withResolved(property, typeSer, ser, _forceTypeInformation);
            }
            return this;
        }
    
        /*
        /**********************************************************
        /* Actual serialization
        /**********************************************************
         */
        
        @Override
        public void serialize(Object bean, JsonGenerator gen, SerializerProvider ctxt) throws IOException
        {
            Object value;
            try {
                value = _accessor.getValue(bean);
            } catch (Exception e) {
                value = null;
                wrapAndThrow(ctxt, e, bean, _accessor.getName() + "()");
            }
    
            if (value == null) {
                ctxt.defaultSerializeNull(gen);
            } else {
                JsonSerializer<Object> ser = _valueSerializer;
                if (ser == null) {
                    ser = _findDynamicSerializer(ctxt, value.getClass());
                }
                if (_valueTypeSerializer != null) {
                    ser.serializeWithType(value, gen, ctxt, _valueTypeSerializer);
                } else {
                    ser.serialize(value, gen, ctxt);
                }
            }
        }
    
        @Override
        public void serializeWithType(Object bean, JsonGenerator gen, SerializerProvider ctxt,
                TypeSerializer typeSer0) throws IOException
        {
            // Regardless of other parts, first need to find value to serialize:
            Object value;
            try {
                value = _accessor.getValue(bean);
            } catch (Exception e) {
                value = null;
                wrapAndThrow(ctxt, e, bean, _accessor.getName() + "()");
            }
    
            // and if we got null, can also just write it directly
            if (value == null) {
                ctxt.defaultSerializeNull(gen);
                return;
            }
            JsonSerializer<Object> ser = _valueSerializer;
            if (ser == null) { // no serializer yet? Need to fetch
                ser = _findDynamicSerializer(ctxt, value.getClass());
            } else {
                // 09-Dec-2010, tatu: To work around natural type's refusal to add type info, we do
                //    this (note: type is for the wrapper type, not enclosed value!)
                if (_forceTypeInformation) {
                    // Confusing? Type id is for POJO and NOT for value returned by JsonValue accessor...
                    WritableTypeId typeIdDef = typeSer0.writeTypePrefix(gen,
                            typeSer0.typeId(bean, JsonToken.VALUE_STRING));
                    ser.serialize(value, gen, ctxt);
                    typeSer0.writeTypeSuffix(gen, typeIdDef);
    
                    return;
                }
            }
            // 28-Sep-2016, tatu: As per [databind#1385], we do need to do some juggling
            //    to use different Object for type id (logical type) and actual serialization
            //    (delegate type).
            TypeSerializerRerouter rr = new TypeSerializerRerouter(typeSer0, bean);
            ser.serializeWithType(value, gen, ctxt, rr);
        }
    
        /*
        /**********************************************************
        /* Schema generation
        /**********************************************************
         */
    
        @SuppressWarnings("deprecation")
        @Override
        public JsonNode getSchema(SerializerProvider ctxt, Type typeHint)
            throws JsonMappingException
        {
            if (_valueSerializer instanceof SchemaAware) {
                return ((SchemaAware)_valueSerializer).getSchema(ctxt, null);
            }
            return com.fasterxml.jackson.databind.jsonschema.JsonSchema.getDefaultSchemaNode();
        }
    
        @Override
        public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
            throws JsonMappingException
        {
            /* 27-Apr-2015, tatu: First things first; for JSON Schema introspection,
             *    Enum types that use `@JsonValue` are special (but NOT necessarily
             *    anything else that RETURNS an enum!)
             *    So we will need to add special
             *    handling here (see https://github.com/FasterXML/jackson-module-jsonSchema/issues/57
             *    for details).
             *    
             *    Note that meaning of JsonValue, then, is very different for Enums. Sigh.
             */
            Class<?> declaring = _accessor.getDeclaringClass();
            if ((declaring != null) && ClassUtil.isEnumType(declaring)) {
                if (_acceptJsonFormatVisitorForEnum(visitor, typeHint, declaring)) {
                    return;
                }
            }
            JsonSerializer<Object> ser = _valueSerializer;
            if (ser == null) {
                ser = visitor.getProvider().findTypedValueSerializer(_valueType, false, _property);
                if (ser == null) { // can this ever occur?
                    visitor.expectAnyFormat(typeHint);
                    return;
                }
            }
            ser.acceptJsonFormatVisitor(visitor, _valueType);
        }
    
        /**
         * Overridable helper method used for special case handling of schema information for
         * Enums.
         * 
         * @return True if method handled callbacks; false if not; in latter case caller will
         *   send default callbacks
         *
         * @since 2.6
         */
        protected boolean _acceptJsonFormatVisitorForEnum(JsonFormatVisitorWrapper visitor,
                JavaType typeHint, Class<?> enumType)
            throws JsonMappingException
        {
            // Copied from EnumSerializer#acceptJsonFormatVisitor
            JsonStringFormatVisitor stringVisitor = visitor.expectStringFormat(typeHint);
            if (stringVisitor != null) {
                Set<String> enums = new LinkedHashSet<String>();
                for (Object en : enumType.getEnumConstants()) {
                    try {
                        // 21-Apr-2016, tatu: This is convoluted to the max, but essentially we
                        //   call `@JsonValue`-annotated accessor method on all Enum members,
                        //   so it all "works out". To some degree.
                        enums.add(String.valueOf(_accessor.getValue(en)));
                    } catch (Exception e) {
                        Throwable t = e;
                        while (t instanceof InvocationTargetException && t.getCause() != null) {
                            t = t.getCause();
                        }
                        ClassUtil.throwIfError(t);
                        throw JsonMappingException.wrapWithPath(t, en, _accessor.getName() + "()");
                    }
                }
                stringVisitor.enumTypes(enums);
            }
            return true;
        }
    
        /*
        /**********************************************************
        /* Other internal helper methods
        /**********************************************************
         */
    
        protected boolean isNaturalTypeWithStdHandling(Class<?> rawType, JsonSerializer<?> ser)
        {
            // First: do we have a natural type being handled?
            if (rawType.isPrimitive()) {
                if (rawType != Integer.TYPE && rawType != Boolean.TYPE && rawType != Double.TYPE) {
                    return false;
                }
            } else {
                if (rawType != String.class &&
                        rawType != Integer.class && rawType != Boolean.class && rawType != Double.class) {
                    return false;
                }
            }
            return isDefaultSerializer(ser);
        }
    
        // @since 2.12
        protected JsonSerializer<Object> _findDynamicSerializer(SerializerProvider ctxt,
                Class<?> valueClass) throws JsonMappingException
        {
            JsonSerializer<Object> serializer = _dynamicSerializers.serializerFor(valueClass);
            if (serializer == null) {
                if (_valueType.hasGenericTypes()) {
                    final JavaType fullType = ctxt.constructSpecializedType(_valueType, valueClass);
                    serializer = ctxt.findPrimaryPropertySerializer(fullType, _property);
                    PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(fullType, serializer);
                    _dynamicSerializers = result.map;
                } else {
                    serializer = ctxt.findPrimaryPropertySerializer(valueClass, _property);
                    PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(valueClass, serializer);
                    _dynamicSerializers = result.map;
                }
            }
            return serializer;
    
            /*
            if (_valueType.hasGenericTypes()) {
                JavaType fullType = ctxt.constructSpecializedType(_valueType, valueClass);
                // 31-Oct-2020, tatu: Should not get typed/root serializer, but for now has to do:
                serializer = ctxt.findTypedValueSerializer(fullType, false, _property);
                PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(fullType, serializer);
                // did we get a new map of serializers? If so, start using it
                _dynamicSerializers = result.map;
                return serializer;
            } else {
                // 31-Oct-2020, tatu: Should not get typed/root serializer, but for now has to do:
                serializer = ctxt.findTypedValueSerializer(valueClass, false, _property);
                PropertySerializerMap.SerializerAndMapResult result = _dynamicSerializers.addSerializer(valueClass, serializer);
                // did we get a new map of serializers? If so, start using it
                _dynamicSerializers = result.map;
                return serializer;
            }
            */
        }
    
        /*
        /**********************************************************
        /* Standard method overrides
        /**********************************************************
         */
    
        @Override
        public String toString() {
            return "(@JsonValue serializer for method " + _accessor.getDeclaringClass() + "#" + _accessor.getName() + ")";
        }
    
        /*
        /**********************************************************
        /* Helper class
        /**********************************************************
         */
    
        /**
         * Silly little wrapper class we need to re-route type serialization so that we can
         * override Object to use for type id (logical type) even when asking serialization
         * of something else (delegate type)
         */
        static class TypeSerializerRerouter
            extends TypeSerializer
        {
            protected final TypeSerializer _typeSerializer;
            protected final Object _forObject;
    
            public TypeSerializerRerouter(TypeSerializer ts, Object ob) {
                _typeSerializer = ts;
                _forObject = ob;
            }
    
            @Override
            public TypeSerializer forProperty(BeanProperty prop) { // should never get called
                throw new UnsupportedOperationException();
            }
    
            @Override
            public As getTypeInclusion() {
                return _typeSerializer.getTypeInclusion();
            }
    
            @Override
            public String getPropertyName() {
                return _typeSerializer.getPropertyName();
            }
    
            @Override
            public TypeIdResolver getTypeIdResolver() {
                return _typeSerializer.getTypeIdResolver();
            }
    
            // // // New Write API, 2.9+
            
            @Override // since 2.9
            public WritableTypeId writeTypePrefix(JsonGenerator g,
                    WritableTypeId typeId) throws IOException {
                // 28-Jun-2017, tatu: Important! Need to "override" value
                typeId.forValue = _forObject;
                return _typeSerializer.writeTypePrefix(g, typeId);
            }
    
            @Override // since 2.9
            public WritableTypeId writeTypeSuffix(JsonGenerator g,
                    WritableTypeId typeId) throws IOException {
                // NOTE: already overwrote value object so:
                return _typeSerializer.writeTypeSuffix(g, typeId);
            }
    
            // // // Old Write API, pre-2.9
    
            @Override
            @Deprecated
            public void writeTypePrefixForScalar(Object value, JsonGenerator gen) throws IOException {
                _typeSerializer.writeTypePrefixForScalar(_forObject, gen);
            }
    
            @Override
            @Deprecated
            public void writeTypePrefixForObject(Object value, JsonGenerator gen) throws IOException {
                _typeSerializer.writeTypePrefixForObject(_forObject, gen);
            }
    
            @Override
            @Deprecated
            public void writeTypePrefixForArray(Object value, JsonGenerator gen) throws IOException {
                _typeSerializer.writeTypePrefixForArray(_forObject, gen);
            }
    
            @Override
            @Deprecated
            public void writeTypeSuffixForScalar(Object value, JsonGenerator gen) throws IOException {
                _typeSerializer.writeTypeSuffixForScalar(_forObject, gen);
            }
    
            @Override
            @Deprecated
            public void writeTypeSuffixForObject(Object value, JsonGenerator gen) throws IOException {
                _typeSerializer.writeTypeSuffixForObject(_forObject, gen);
            }
    
            @Override
            @Deprecated
            public void writeTypeSuffixForArray(Object value, JsonGenerator gen) throws IOException {
                _typeSerializer.writeTypeSuffixForArray(_forObject, gen);
            }
    
            @Override
            @Deprecated
            public void writeTypePrefixForScalar(Object value, JsonGenerator gen, Class<?> type) throws IOException {
                _typeSerializer.writeTypePrefixForScalar(_forObject, gen, type);
            }
    
            @Override
            @Deprecated
            public void writeTypePrefixForObject(Object value, JsonGenerator gen, Class<?> type) throws IOException {
                _typeSerializer.writeTypePrefixForObject(_forObject, gen, type);
            }
    
            @Override
            @Deprecated
            public void writeTypePrefixForArray(Object value, JsonGenerator gen, Class<?> type) throws IOException {
                _typeSerializer.writeTypePrefixForArray(_forObject, gen, type);
            }
    
            /*
            /**********************************************************
            /* Deprecated methods (since 2.9)
            /**********************************************************
             */
    
            @Override
            @Deprecated
            public void writeCustomTypePrefixForScalar(Object value, JsonGenerator gen, String typeId)
                    throws IOException {
                _typeSerializer.writeCustomTypePrefixForScalar(_forObject, gen, typeId);
            }
    
            @Override
            @Deprecated
            public void writeCustomTypePrefixForObject(Object value, JsonGenerator gen, String typeId) throws IOException {
                _typeSerializer.writeCustomTypePrefixForObject(_forObject, gen, typeId);
            }
    
            @Override
            @Deprecated
            public void writeCustomTypePrefixForArray(Object value, JsonGenerator gen, String typeId) throws IOException {
                _typeSerializer.writeCustomTypePrefixForArray(_forObject, gen, typeId);
            }
    
            @Override
            @Deprecated
            public void writeCustomTypeSuffixForScalar(Object value, JsonGenerator gen, String typeId) throws IOException {
                _typeSerializer.writeCustomTypeSuffixForScalar(_forObject, gen, typeId);
            }
    
            @Override
            @Deprecated
            public void writeCustomTypeSuffixForObject(Object value, JsonGenerator gen, String typeId) throws IOException {
                _typeSerializer.writeCustomTypeSuffixForObject(_forObject, gen, typeId);
            }
    
            @Override
            @Deprecated
            public void writeCustomTypeSuffixForArray(Object value, JsonGenerator gen, String typeId) throws IOException {
                _typeSerializer.writeCustomTypeSuffixForArray(_forObject, gen, typeId);
            }
        }
    }
    

    com/fasterxml/jackson/databind/ser/std/JsonValueSerializer.java

     

    ⇒ Jackson Annotations Source Code

    ⇐ Download and Install Jackson Binary Package

    ⇑ Downloading and Reviewing jackson-*.jar

    ⇑⇑ Jackson - Java JSON library

    2022-03-29, 32113👍, 0💬