com.fitbur.jackson.databind.JsonSerializer Maven / Gradle / Ivy
package com.fitbur.jackson.databind;
import java.io.IOException;
import java.util.Iterator;
import com.fitbur.jackson.core.*;
import com.fitbur.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
import com.fitbur.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fitbur.jackson.databind.jsontype.TypeSerializer;
import com.fitbur.jackson.databind.ser.PropertyWriter;
import com.fitbur.jackson.databind.util.ClassUtil;
import com.fitbur.jackson.databind.util.NameTransformer;
/**
* Abstract class that defines API used by {@link ObjectMapper} (and
* other chained {@link JsonSerializer}s too) to serialize Objects of
* arbitrary types into JSON, using provided {@link JsonGenerator}.
* {@link com.fitbur.jackson.databind.ser.std.StdSerializer} instead
* of this class, since it will implement many of optional
* methods of this class.
*
* NOTE: various serialize
methods are never (to be) called
* with null values -- caller must handle null values, usually
* by calling {@link SerializerProvider#findNullValueSerializer} to obtain
* serializer to use.
* This also means that custom serializers can not be directly used to change
* the output to produce when serializing null values.
*
* If serializer is an aggregate one -- meaning it delegates handling of some
* of its contents by using other serializer(s) -- it typically also needs
* to implement {@link com.fitbur.jackson.databind.ser.ResolvableSerializer},
* which can locate secondary serializers needed. This is important to allow dynamic
* overrides of serializers; separate call interface is needed to separate
* resolution of secondary serializers (which may have cyclic link back
* to serializer itself, directly or indirectly).
*
* In addition, to support per-property annotations (to configure aspects
* of serialization on per-property basis), serializers may want
* to implement
* {@link com.fitbur.jackson.databind.ser.ContextualSerializer},
* which allows specialization of serializers: call to
* {@link com.fitbur.jackson.databind.ser.ContextualSerializer#createContextual}
* is passed information on property, and can create a newly configured
* serializer for handling that particular property.
*
* If both
* {@link com.fitbur.jackson.databind.ser.ResolvableSerializer} and
* {@link com.fitbur.jackson.databind.ser.ContextualSerializer}
* are implemented, resolution of serializers occurs before
* contextualization.
*/
public abstract class JsonSerializer
implements JsonFormatVisitable // since 2.1
{
/*
/**********************************************************
/* Fluent factory methods for constructing decorated versions
/**********************************************************
*/
/**
* Method that will return serializer instance that produces
* "unwrapped" serialization, if applicable for type being
* serialized (which is the case for some serializers
* that produce JSON Objects as output).
* If no unwrapped serializer can be constructed, will simply
* return serializer as-is.
*
* Default implementation just returns serializer as-is,
* indicating that no unwrapped variant exists
*
* @param unwrapper Name transformation to use to convert between names
* of unwrapper properties
*/
public JsonSerializer unwrappingSerializer(NameTransformer unwrapper) {
return this;
}
/**
* Method that can be called to try to replace serializer this serializer
* delegates calls to. If not supported (either this serializer does not
* delegate anything; or it does not want any changes), should either
* throw {@link UnsupportedOperationException} (if operation does not
* make sense or is not allowed); or return this serializer as is.
*
* @since 2.1
*/
public JsonSerializer replaceDelegatee(JsonSerializer> delegatee) {
throw new UnsupportedOperationException();
}
/**
* Mutant factory method that is called if contextual configuration indicates that
* a specific filter (as specified by filterId
) is to be used for
* serialization.
*
* Default implementation simply returns this
; sub-classes that do support
* filtering will need to create and return new instance if filter changes.
*
* @since 2.6
*/
public JsonSerializer> withFilterId(Object filterId) {
return this;
}
/*
/**********************************************************
/* Serialization methods
/**********************************************************
*/
/**
* Method that can be called to ask implementation to serialize
* values of type this serializer handles.
*
* @param value Value to serialize; can not be null.
* @param gen Generator used to output resulting Json content
* @param serializers Provider that can be used to get serializers for
* serializing Objects value contains, if any.
*/
public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException;
/**
* Method that can be called to ask implementation to serialize
* values of type this serializer handles, using specified type serializer
* for embedding necessary type information.
*
* Default implementation will throw {@link UnsupportedOperationException}
* to indicate that proper type handling needs to be implemented.
*
* For simple datatypes written as a single scalar value (JSON String, Number, Boolean),
* implementation would look like:
*
* // note: method to call depends on whether this type is serialized as JSON scalar, object or Array!
* typeSer.writeTypePrefixForScalar(value, gen);
* serialize(value, gen, provider);
* typeSer.writeTypeSuffixForScalar(value, gen);
*
* and implementations for type serialized as JSON Arrays or Objects would differ slightly,
* as START-ARRAY
/END-ARRAY
and
* START-OBJECT
/END-OBJECT
pairs
* need to be properly handled with respect to serializing of contents.
*
* @param value Value to serialize; can not be null.
* @param gen Generator used to output resulting Json content
* @param serializers Provider that can be used to get serializers for
* serializing Objects value contains, if any.
* @param typeSer Type serializer to use for including type information
*/
public void serializeWithType(T value, JsonGenerator gen, SerializerProvider serializers,
TypeSerializer typeSer)
throws IOException
{
Class> clz = handledType();
if (clz == null) {
clz = value.getClass();
}
throw serializers.mappingException("Type id handling not implemented for type %s (by serializer of type %s)",
clz.getName(), getClass().getName());
}
/*
/**********************************************************
/* Other accessors
/**********************************************************
*/
/**
* Method for accessing type of Objects this serializer can handle.
* Note that this information is not guaranteed to be exact -- it
* may be a more generic (super-type) -- but it should not be
* incorrect (return a non-related type).
*
* Default implementation will return null, which essentially means
* same as returning Object.class
would; that is, that
* nothing is known about handled type.
*
*/
public Class handledType() { return null; }
/**
* Method called to check whether given serializable value is
* considered "empty" value (for purposes of suppressing serialization
* of empty values).
*
* Default implementation will consider only null values to be empty.
*
* @since 2.0
*
* @deprecated Since 2.5 Use {@link #isEmpty(SerializerProvider, Object)} instead;
* will be removed from 2.8
*/
@Deprecated
public boolean isEmpty(T value) {
return isEmpty(null, value);
}
/**
* Method called to check whether given serializable value is
* considered "empty" value (for purposes of suppressing serialization
* of empty values).
*
* Default implementation will consider only null values to be empty.
*
* NOTE: replaces {@link #isEmpty(Object)}, deprecated in 2.5
*
* @since 2.5
*/
public boolean isEmpty(SerializerProvider provider, T value) {
return (value == null);
}
/**
* Method that can be called to see whether this serializer instance
* will use Object Id to handle cyclic references.
*/
public boolean usesObjectId() {
return false;
}
/**
* Accessor for checking whether this serializer is an
* "unwrapping" serializer; this is necessary to know since
* it may also require caller to suppress writing of the
* leading property name.
*/
public boolean isUnwrappingSerializer() {
return false;
}
/**
* Accessor that can be used to determine if this serializer uses
* another serializer for actual serialization, by delegating
* calls. If so, will return immediate delegate (which itself may
* delegate to further serializers); otherwise will return null.
*
* @return Serializer this serializer delegates calls to, if null;
* null otherwise.
*
* @since 2.1
*/
public JsonSerializer> getDelegatee() {
return null;
}
/**
* Accessor for iterating over logical properties that the type
* handled by this serializer has, from serialization perspective.
* Actual type of properties, if any, will be
* {@link com.fitbur.jackson.databind.ser.BeanPropertyWriter}.
* Of standard Jackson serializers, only {@link com.fitbur.jackson.databind.ser.BeanSerializer}
* exposes properties.
*
* @since 2.6
*/
public Iterator properties() {
return ClassUtil.emptyIterator();
}
/*
/**********************************************************
/* Default JsonFormatVisitable implementation
/**********************************************************
*/
/**
* Default implementation simply calls {@link JsonFormatVisitorWrapper#expectAnyFormat(JavaType)}.
*
* @since 2.1
*/
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType type)
throws JsonMappingException
{
if (visitor != null) visitor.expectAnyFormat(type);
}
/*
/**********************************************************
/* Helper class(es)
/**********************************************************
*/
/**
* This marker class is only to be used with annotations, to
* indicate that no serializer is configured.
*
* Specifically, this class is to be used as the marker for
* annotation {@link com.fitbur.jackson.databind.annotation.JsonSerialize}.
*/
public abstract static class None
extends JsonSerializer