package com.esotericsoftware.kryo.serializers; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Currency; import java.util.Date; import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TimeZone; import java.util.TreeMap; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.KryoException; import com.esotericsoftware.kryo.KryoSerializable; import com.esotericsoftware.kryo.Registration; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; import static com.esotericsoftware.kryo.Kryo.*; /** Contains many serializer classes that are provided by {@link Kryo#addDefaultSerializer(Class, Class) default}. * @author Nathan Sweet <misc@n4te.com> */ public class DefaultSerializers { static public class BooleanSerializer extends Serializer<Boolean> { { setImmutable(true); } public void write (Kryo kryo, Output output, Boolean object) { output.writeBoolean(object); } public Boolean read (Kryo kryo, Input input, Class<Boolean> type) { return input.readBoolean(); } } static public class ByteSerializer extends Serializer<Byte> { { setImmutable(true); } public void write (Kryo kryo, Output output, Byte object) { output.writeByte(object); } public Byte read (Kryo kryo, Input input, Class<Byte> type) { return input.readByte(); } } static public class CharSerializer extends Serializer<Character> { { setImmutable(true); } public void write (Kryo kryo, Output output, Character object) { output.writeChar(object); } public Character read (Kryo kryo, Input input, Class<Character> type) { return input.readChar(); } } static public class ShortSerializer extends Serializer<Short> { { setImmutable(true); } public void write (Kryo kryo, Output output, Short object) { output.writeShort(object); } public Short read (Kryo kryo, Input input, Class<Short> type) { return input.readShort(); } } static public class IntSerializer extends Serializer<Integer> { { setImmutable(true); } public void write (Kryo kryo, Output output, Integer object) { output.writeInt(object, false); } public Integer read (Kryo kryo, Input input, Class<Integer> type) { return input.readInt(false); } } static public class LongSerializer extends Serializer<Long> { { setImmutable(true); } public void write (Kryo kryo, Output output, Long object) { output.writeLong(object, false); } public Long read (Kryo kryo, Input input, Class<Long> type) { return input.readLong(false); } } static public class FloatSerializer extends Serializer<Float> { { setImmutable(true); } public void write (Kryo kryo, Output output, Float object) { output.writeFloat(object); } public Float read (Kryo kryo, Input input, Class<Float> type) { return input.readFloat(); } } static public class DoubleSerializer extends Serializer<Double> { { setImmutable(true); } public void write (Kryo kryo, Output output, Double object) { output.writeDouble(object); } public Double read (Kryo kryo, Input input, Class<Double> type) { return input.readDouble(); } } /** @see Output#writeString(String) */ static public class StringSerializer extends Serializer<String> { { setImmutable(true); setAcceptsNull(true); } public void write (Kryo kryo, Output output, String object) { output.writeString(object); } public String read (Kryo kryo, Input input, Class<String> type) { return input.readString(); } } static public class BigIntegerSerializer extends Serializer<BigInteger> { { setImmutable(true); setAcceptsNull(true); } public void write (Kryo kryo, Output output, BigInteger object) { if (object == null) { output.writeByte(NULL); return; } BigInteger value = (BigInteger)object; byte[] bytes = value.toByteArray(); output.writeInt(bytes.length + 1, true); output.writeBytes(bytes); } public BigInteger read (Kryo kryo, Input input, Class<BigInteger> type) { int length = input.readInt(true); if (length == NULL) return null; byte[] bytes = input.readBytes(length - 1); return new BigInteger(bytes); } } static public class BigDecimalSerializer extends Serializer<BigDecimal> { private BigIntegerSerializer bigIntegerSerializer = new BigIntegerSerializer(); { setAcceptsNull(true); setImmutable(true); } public void write (Kryo kryo, Output output, BigDecimal object) { if (object == null) { output.writeByte(NULL); return; } BigDecimal value = (BigDecimal)object; bigIntegerSerializer.write(kryo, output, value.unscaledValue()); output.writeInt(value.scale(), false); } public BigDecimal read (Kryo kryo, Input input, Class<BigDecimal> type) { BigInteger unscaledValue = bigIntegerSerializer.read(kryo, input, null); if (unscaledValue == null) return null; int scale = input.readInt(false); return new BigDecimal(unscaledValue, scale); } } static public class ClassSerializer extends Serializer<Class> { { setImmutable(true); setAcceptsNull(true); } public void write (Kryo kryo, Output output, Class object) { kryo.writeClass(output, object); } public Class read (Kryo kryo, Input input, Class<Class> type) { return kryo.readClass(input).getType(); } } static public class DateSerializer extends Serializer<Date> { public void write (Kryo kryo, Output output, Date object) { output.writeLong(object.getTime(), true); } public Date read (Kryo kryo, Input input, Class<Date> type) { return new Date(input.readLong(true)); } public Date copy (Kryo kryo, Date original) { return new Date(original.getTime()); } } static public class EnumSerializer extends Serializer<Enum> { { setImmutable(true); setAcceptsNull(true); } private Object[] enumConstants; public EnumSerializer (Class<? extends Enum> type) { enumConstants = type.getEnumConstants(); if (enumConstants == null) throw new IllegalArgumentException("The type must be an enum: " + type); } public void write (Kryo kryo, Output output, Enum object) { if (object == null) { output.writeByte(NULL); return; } output.writeInt(object.ordinal() + 1, true); } public Enum read (Kryo kryo, Input input, Class<Enum> type) { int ordinal = input.readInt(true); if (ordinal == NULL) return null; ordinal--; if (ordinal < 0 || ordinal > enumConstants.length - 1) throw new KryoException("Invalid ordinal for enum \"" + type.getName() + "\": " + ordinal); Object constant = enumConstants[ordinal]; return (Enum)constant; } } static public class EnumSetSerializer extends Serializer<EnumSet> { public void write (Kryo kryo, Output output, EnumSet object) { if (object.isEmpty()) throw new KryoException("An empty EnumSet cannot be serialized."); Serializer serializer = kryo.writeClass(output, object.iterator().next().getClass()).getSerializer(); output.writeInt(object.size(), true); for (Object element : object) serializer.write(kryo, output, element); } public EnumSet read (Kryo kryo, Input input, Class<EnumSet> type) { Registration registration = kryo.readClass(input); EnumSet object = EnumSet.noneOf(registration.getType()); Serializer serializer = registration.getSerializer(); int length = input.readInt(true); for (int i = 0; i < length; i++) object.add(serializer.read(kryo, input, null)); return object; } public EnumSet copy (Kryo kryo, EnumSet original) { return EnumSet.copyOf(original); } } /** @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CurrencySerializer extends Serializer<Currency> { { setImmutable(true); setAcceptsNull(true); } public void write (Kryo kryo, Output output, Currency object) { output.writeString(object == null ? null : object.getCurrencyCode()); } public Currency read (Kryo kryo, Input input, Class<Currency> type) { String currencyCode = input.readString(); if (currencyCode == null) return null; return Currency.getInstance(currencyCode); } } /** @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class StringBufferSerializer extends Serializer<StringBuffer> { { setAcceptsNull(true); } public void write (Kryo kryo, Output output, StringBuffer object) { output.writeString(object); } public StringBuffer read (Kryo kryo, Input input, Class<StringBuffer> type) { String value = input.readString(); if (value == null) return null; return new StringBuffer(value); } public StringBuffer copy (Kryo kryo, StringBuffer original) { return new StringBuffer(original); } } /** @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class StringBuilderSerializer extends Serializer<StringBuilder> { { setAcceptsNull(true); } public void write (Kryo kryo, Output output, StringBuilder object) { output.writeString(object); } public StringBuilder read (Kryo kryo, Input input, Class<StringBuilder> type) { return input.readStringBuilder(); } public StringBuilder copy (Kryo kryo, StringBuilder original) { return new StringBuilder(original); } } static public class KryoSerializableSerializer extends Serializer<KryoSerializable> { public void write (Kryo kryo, Output output, KryoSerializable object) { object.write(kryo, output); } public KryoSerializable read (Kryo kryo, Input input, Class<KryoSerializable> type) { KryoSerializable object = kryo.newInstance(type); kryo.reference(object); object.read(kryo, input); return object; } } /** Serializer for lists created via {@link Collections#emptyList()} or that were just assigned the * {@link Collections#EMPTY_LIST}. * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CollectionsEmptyListSerializer extends Serializer { { setImmutable(true); } public void write (Kryo kryo, Output output, Object object) { } public Object read (Kryo kryo, Input input, Class type) { return Collections.EMPTY_LIST; } } /** Serializer for maps created via {@link Collections#emptyMap()} or that were just assigned the {@link Collections#EMPTY_MAP}. * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CollectionsEmptyMapSerializer extends Serializer { { setImmutable(true); } public void write (Kryo kryo, Output output, Object object) { } public Object read (Kryo kryo, Input input, Class type) { return Collections.EMPTY_MAP; } } /** Serializer for sets created via {@link Collections#emptySet()} or that were just assigned the {@link Collections#EMPTY_SET}. * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CollectionsEmptySetSerializer extends Serializer { { setImmutable(true); } public void write (Kryo kryo, Output output, Object object) { } public Object read (Kryo kryo, Input input, Class type) { return Collections.EMPTY_SET; } } /** Serializer for lists created via {@link Collections#singletonList(Object)}. * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CollectionsSingletonListSerializer extends Serializer<List> { { setImmutable(true); } public void write (Kryo kryo, Output output, List object) { kryo.writeClassAndObject(output, object.get(0)); } public List read (Kryo kryo, Input input, Class type) { return Collections.singletonList(kryo.readClassAndObject(input)); } } /** Serializer for maps created via {@link Collections#singletonMap(Object, Object)}. * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CollectionsSingletonMapSerializer extends Serializer<Map> { { setImmutable(true); } public void write (Kryo kryo, Output output, Map object) { Entry entry = (Entry)object.entrySet().iterator().next(); kryo.writeClassAndObject(output, entry.getKey()); kryo.writeClassAndObject(output, entry.getValue()); } public Map read (Kryo kryo, Input input, Class type) { Object key = kryo.readClassAndObject(input); Object value = kryo.readClassAndObject(input); return Collections.singletonMap(key, value); } } /** Serializer for sets created via {@link Collections#singleton(Object)}. * @author <a href="mailto:martin.grotzke@javakaffee.de">Martin Grotzke</a> */ static public class CollectionsSingletonSetSerializer extends Serializer<Set> { { setImmutable(true); } public void write (Kryo kryo, Output output, Set object) { kryo.writeClassAndObject(output, object.iterator().next()); } public Set read (Kryo kryo, Input input, Class type) { return Collections.singleton(kryo.readClassAndObject(input)); } } /** Serializer for {@link TimeZone}. Assumes the timezones are immutable. * @author serverperformance */ static public class TimeZoneSerializer extends Serializer<TimeZone> { { setImmutable(true); } public void write (Kryo kryo, Output output, TimeZone object) { output.writeString(object.getID()); } public TimeZone read (Kryo kryo, Input input, Class<TimeZone> type) { return TimeZone.getTimeZone(input.readString()); } } /** Serializer for {@link GregorianCalendar}, java.util.JapaneseImperialCalendar, and sun.util.BuddhistCalendar. * @author serverperformance */ static public class CalendarSerializer extends Serializer<Calendar> { // The default value of gregorianCutover. static private final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L; TimeZoneSerializer timeZoneSerializer = new TimeZoneSerializer(); public void write (Kryo kryo, Output output, Calendar object) { timeZoneSerializer.write(kryo, output, object.getTimeZone()); // can't be null output.writeLong(object.getTimeInMillis(), true); output.writeBoolean(object.isLenient()); output.writeInt(object.getFirstDayOfWeek(), true); output.writeInt(object.getMinimalDaysInFirstWeek(), true); if (object instanceof GregorianCalendar) output.writeLong(((GregorianCalendar)object).getGregorianChange().getTime(), false); else output.writeLong(DEFAULT_GREGORIAN_CUTOVER, false); } public Calendar read (Kryo kryo, Input input, Class<Calendar> type) { Calendar result = Calendar.getInstance(timeZoneSerializer.read(kryo, input, TimeZone.class)); result.setTimeInMillis(input.readLong(true)); result.setLenient(input.readBoolean()); result.setFirstDayOfWeek(input.readInt(true)); result.setMinimalDaysInFirstWeek(input.readInt(true)); long gregorianChange = input.readLong(false); if (gregorianChange != DEFAULT_GREGORIAN_CUTOVER) if (result instanceof GregorianCalendar) ((GregorianCalendar)result).setGregorianChange(new Date(gregorianChange)); return result; } public Calendar copy (Kryo kryo, Calendar original) { return (Calendar)original.clone(); } } static public class TreeMapSerializer extends MapSerializer { public void write (Kryo kryo, Output output, Map map) { TreeMap treeMap = (TreeMap)map; boolean references = kryo.setReferences(false); kryo.writeClassAndObject(output, treeMap.comparator()); kryo.setReferences(references); super.write(kryo, output, map); } protected Map create (Kryo kryo, Input input, Class<Map> type) { return new TreeMap((Comparator)kryo.readClassAndObject(input)); } protected Map createCopy (Kryo kryo, Map original) { return new TreeMap(((TreeMap)original).comparator()); } } }