![JAR search and dependency download from the Maven repository](/logo.png)
org.codehaus.jackson.map.ser.BasicSerializerFactory Maven / Gradle / Ivy
package org.codehaus.jackson.map.ser;
import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import org.codehaus.jackson.*;
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.introspect.Annotated;
import org.codehaus.jackson.map.introspect.BasicBeanDescription;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.map.util.ClassUtil;
import org.codehaus.jackson.map.util.Provider;
import org.codehaus.jackson.node.ObjectNode;
import org.codehaus.jackson.schema.JsonSerializableSchema;
/**
* Factory class that can provide serializers for standard JDK classes,
* as well as custom classes that extend standard classes or implement
* one of "well-known" interfaces (such as {@link java.util.Collection}).
*
* Since all the serializers are eagerly instantiated, and there is
* no additional introspection or customazibility of these types,
* this factory is stateless. This means that other delegating
* factories (or {@link SerializerProvider}s) can just use the
* shared singleton instance via static {@link #instance} field.
*/
public class BasicSerializerFactory
extends SerializerFactory
{
/*
////////////////////////////////////////////////////////////
// Configuration, lookup tables/maps
////////////////////////////////////////////////////////////
*/
/**
* Since these are all JDK classes, we shouldn't have to worry
* about ClassLoader used to load them. Rather, we can just
* use the class name, and keep things simple and efficient.
*/
final static HashMap> _concrete =
new HashMap>();
/**
* There are also standard interfaces and abstract classes
* that we need to support without knowing conrecte implementation
* classes.
*/
final static ArrayList _abstractSerializers =
new ArrayList();
static {
/* String and string-like types (note: date types explicitly
* not included -- can use either textual or numeric serialization)
*/
_concrete.put(String.class.getName(), new StringSerializer());
final ToStringSerializer sls = ToStringSerializer.instance;
_concrete.put(StringBuffer.class.getName(), sls);
_concrete.put(StringBuilder.class.getName(), sls);
_concrete.put(Character.class.getName(), sls);
_concrete.put(Character.TYPE.getName(), sls);
// Primitives/wrappers for primitives (primitives needed for Beans)
_concrete.put(Boolean.TYPE.getName(), new BooleanSerializer(true));
_concrete.put(Boolean.class.getName(), new BooleanSerializer(false));
final IntegerSerializer intS = new IntegerSerializer();
_concrete.put(Integer.class.getName(), intS);
_concrete.put(Integer.TYPE.getName(), intS);
_concrete.put(Long.class.getName(), LongSerializer.instance);
_concrete.put(Long.TYPE.getName(), LongSerializer.instance);
_concrete.put(Byte.class.getName(), IntLikeSerializer.instance);
_concrete.put(Byte.TYPE.getName(), IntLikeSerializer.instance);
_concrete.put(Short.class.getName(), IntLikeSerializer.instance);
_concrete.put(Short.TYPE.getName(), IntLikeSerializer.instance);
// Numbers, limited length floating point
_concrete.put(Float.class.getName(), FloatSerializer.instance);
_concrete.put(Float.TYPE.getName(), FloatSerializer.instance);
_concrete.put(Double.class.getName(), DoubleSerializer.instance);
_concrete.put(Double.TYPE.getName(), DoubleSerializer.instance);
// Other numbers, more complicated
final NumberSerializer ns = new NumberSerializer();
_concrete.put(BigInteger.class.getName(), ns);
_concrete.put(BigDecimal.class.getName(), ns);
/* Other discrete non-container types:
* first, Date/Time zoo:
*/
_concrete.put(Calendar.class.getName(), CalendarSerializer.instance);
_concrete.put(java.util.Date.class.getName(), UtilDateSerializer.instance);
_concrete.put(java.sql.Date.class.getName(), new SqlDateSerializer());
_concrete.put(java.sql.Time.class.getName(), new SqlTimeSerializer());
// note: timestamps are very similar to java.util.Date, thus serialized as such
_concrete.put(java.sql.Timestamp.class.getName(), UtilDateSerializer.instance);
// Class.class
_concrete.put(Class.class.getName(), new ClassSerializer());
// Arrays of various types (including common object types)
_concrete.put(boolean[].class.getName(), new ArraySerializers.BooleanArraySerializer());
_concrete.put(byte[].class.getName(), new ArraySerializers.ByteArraySerializer());
_concrete.put(char[].class.getName(), new ArraySerializers.CharArraySerializer());
_concrete.put(short[].class.getName(), new ArraySerializers.ShortArraySerializer());
_concrete.put(int[].class.getName(), new ArraySerializers.IntArraySerializer());
_concrete.put(long[].class.getName(), new ArraySerializers.LongArraySerializer());
_concrete.put(float[].class.getName(), new ArraySerializers.FloatArraySerializer());
_concrete.put(double[].class.getName(), new ArraySerializers.DoubleArraySerializer());
_concrete.put(Object[].class.getName(), ArraySerializers.ObjectArraySerializer.instance);
_concrete.put(String[].class.getName(), new ArraySerializers.StringArraySerializer());
// And then Java Collection classes
final ContainerSerializers.IndexedListSerializer indListS = ContainerSerializers.IndexedListSerializer.instance;
final ContainerSerializers.CollectionSerializer collectionS = ContainerSerializers.CollectionSerializer.instance;
_concrete.put(ArrayList.class.getName(), indListS);
_concrete.put(Vector.class.getName(), indListS);
_concrete.put(LinkedList.class.getName(), collectionS);
// (java.util.concurrent has others, but let's allow those to be
// found via slower introspection; too many to enumerate here)
final MapSerializer mapS = MapSerializer.instance;
_concrete.put(HashMap.class.getName(), mapS);
_concrete.put(Hashtable.class.getName(), mapS);
_concrete.put(LinkedHashMap.class.getName(), mapS);
_concrete.put(TreeMap.class.getName(), mapS);
_concrete.put(Properties.class.getName(), mapS);
_concrete.put(HashSet.class.getName(), collectionS);
_concrete.put(LinkedHashSet.class.getName(), collectionS);
_concrete.put(TreeSet.class.getName(), collectionS);
// Finally, couple of oddball types. Not sure if these are really needed but...
_concrete.put(Void.TYPE.getName(), NullSerializer.instance);
// And finally other standard JDK types
for (Map.Entry,JsonSerializer>> en : new JdkSerializers().provide()) {
_concrete.put(en.getKey().getName(), en.getValue());
}
}
static {
/* 21-Nov-2009, tatu: Also, explicit support for basic Joda DateTime;
* and can use same mechanism for javax.xml.datatype types as well.
*/
for (String provStr : new String[] {
"org.codehaus.jackson.map.ext.CoreXMLSerializers"
,"org.codehaus.jackson.map.ext.JodaSerializers"
}) {
Object ob = null;
try {
ob = Class.forName(provStr).newInstance();
}
catch (LinkageError e) { }
// too many different kinds to enumerate here:
catch (Exception e) { }
if (ob != null) {
@SuppressWarnings("unchecked")
Provider,JsonSerializer>>> prov =
(Provider,JsonSerializer>>>) ob;
for (Map.Entry,JsonSerializer>> en : prov.provide()) {
/* 22-Nov-2009, tatu: For now this check suffices... may need
* to use other methods in future
*/
Class> cls = en.getKey();
if (ClassUtil.isConcrete(cls)) {
_concrete.put(en.getKey().getName(), en.getValue());
} else {
_abstractSerializers.add(new SerializerMapping(cls, en.getValue()));
}
}
}
}
}
/*
////////////////////////////////////////////////////////////
// Life cycle
////////////////////////////////////////////////////////////
*/
/**
* Stateless global singleton instance that should be used
* for factories that want to use delegation to access
* standard serializers.
*/
public final static BasicSerializerFactory instance = new BasicSerializerFactory();
/*
////////////////////////////////////////////////////////////
// Life cycle
////////////////////////////////////////////////////////////
*/
/**
* We will provide default constructor to allow sub-classing,
* but make it protected so that no non-singleton instances of
* the class will be instantiated.
*/
protected BasicSerializerFactory() { }
/*
////////////////////////////////////////////////////////////
// JsonSerializerFactory impl
////////////////////////////////////////////////////////////
*/
/**
* Main serializer constructor method. The base implementation within
* this class first calls a fast lookup method that can find serializers
* for well-known JDK classes; and if that fails, a slower one that
* tries to check out which interfaces given Class implements.
* Sub-classes can (and do) change this behavior to alter behavior.
*/
@Override
@SuppressWarnings("unchecked")
public JsonSerializer createSerializer(Class type, SerializationConfig config)
{
// First, fast lookup for exact type:
JsonSerializer> ser = findSerializerByLookup(type, config);
if (ser == null) {
/* and should that fail, slower introspection methods; first
* one that deals with "primary" types
*/
ser = findSerializerByPrimaryType(type, config);
if (ser == null) {
// And if that fails, one with "secondary" traits:
ser = findSerializerByAddonType(type, config);
}
}
return (JsonSerializer) ser;
}
/*
////////////////////////////////////////////////////////////
// Other public methods
////////////////////////////////////////////////////////////
*/
public final JsonSerializer> getNullSerializer() {
return NullSerializer.instance;
}
/*
////////////////////////////////////////////////////////////
// Overridable secondary serializer accessor methods
////////////////////////////////////////////////////////////
*/
/**
* Fast lookup-based accessor method, which will only check for
* type itself, but not consider super-classes or implemented
* interfaces.
*/
public final JsonSerializer> findSerializerByLookup(Class> type, SerializationConfig config)
{
JsonSerializer> ser = _concrete.get(type.getName());
/* 08-Nov-2009, tatus: Some standard types may need customization;
* for now that just means Maps, but in future probably other
* collections as well. For strictly standard types this is
* currently only needed due to mix-in annotations.
*/
if (ser != null ) {
if (ser == MapSerializer.instance) {
return buildMapSerializer(type, config);
}
}
return ser;
}
/**
* Reflection-based serialized find method, which checks if
* given class is a sub-type of one of well-known classes, or implements
* a "primary" interface. Primary here is defined as the main function
* of the Object; as opposed to "add-on" functionality.
*/
public final JsonSerializer> findSerializerByPrimaryType(Class> type, SerializationConfig config)
{
/* Some types are final, and hence not checked here (will
* have been handled by fast method above):
*
* - Boolean
* - String (StringBuffer, StringBuilder)
* - Arrays for primitive types
*
* But we do need to check for
*
* - "primary" interfaces: Enum, Number, JsonSerializable
* - Most collection types
* - java.lang.Number (but is that integral or not?)
*/
if (JsonSerializable.class.isAssignableFrom(type)) {
return SerializableSerializer.instance;
}
if (Map.class.isAssignableFrom(type)) {
return buildMapSerializer(type, config);
}
if (Object[].class.isAssignableFrom(type)) {
return ArraySerializers.ObjectArraySerializer.instance;
}
if (List.class.isAssignableFrom(type)) {
// [JACKSON-220]: need to check for explicit serializer first:
BasicBeanDescription desc = config.introspectClassAnnotations(type);
JsonSerializer> ser = findSerializerFromAnnotation(config, desc.getClassInfo());
if (ser == null) {
if (RandomAccess.class.isAssignableFrom(type)) {
ser = ContainerSerializers.IndexedListSerializer.instance;
} else {
ser = ContainerSerializers.CollectionSerializer.instance;
}
}
return ser;
}
if (Number.class.isAssignableFrom(type)) {
return NumberSerializer.instance;
}
if (Enum.class.isAssignableFrom(type)) {
/* 18-Feb-2009, tatu: Sort of related to [JACKSON-58], it
* was found out that annotations do not work with
* Enum classes.
*/
BasicBeanDescription desc = config.introspectClassAnnotations(type);
JsonSerializer