com.esotericsoftware.kryo.serializers.DefaultSerializers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of redisson-all Show documentation
Show all versions of redisson-all Show documentation
Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC
/* Copyright (c) 2008-2023, Nathan Sweet
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
* - Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
package com.esotericsoftware.kryo.serializers;
import static com.esotericsoftware.kryo.Kryo.*;
import static com.esotericsoftware.kryo.util.Util.*;
import static java.lang.Long.numberOfLeadingZeros;
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 java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Collection;
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.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
/** Contains many serializer classes that are provided by {@link Kryo#addDefaultSerializer(Class, Class) default}.
* @author Nathan Sweet */
public class DefaultSerializers {
public static class VoidSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Object object) {
}
public Object read (Kryo kryo, Input input, Class type) {
return null;
}
}
public static class BooleanSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Boolean object) {
output.writeBoolean(object);
}
public Boolean read (Kryo kryo, Input input, Class extends Boolean> type) {
return input.readBoolean();
}
}
public static class ByteSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Byte object) {
output.writeByte(object);
}
public Byte read (Kryo kryo, Input input, Class extends Byte> type) {
return input.readByte();
}
}
public static class CharSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Character object) {
output.writeChar(object);
}
public Character read (Kryo kryo, Input input, Class extends Character> type) {
return input.readChar();
}
}
public static class ShortSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Short object) {
output.writeShort(object);
}
public Short read (Kryo kryo, Input input, Class extends Short> type) {
return input.readShort();
}
}
public static class IntSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Integer object) {
output.writeInt(object, false);
}
public Integer read (Kryo kryo, Input input, Class extends Integer> type) {
return input.readInt(false);
}
}
public static class LongSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Long object) {
output.writeVarLong(object, false);
}
public Long read (Kryo kryo, Input input, Class extends Long> type) {
return input.readVarLong(false);
}
}
public static class FloatSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Float object) {
output.writeFloat(object);
}
public Float read (Kryo kryo, Input input, Class extends Float> type) {
return input.readFloat();
}
}
public static class DoubleSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Double object) {
output.writeDouble(object);
}
public Double read (Kryo kryo, Input input, Class extends Double> type) {
return input.readDouble();
}
}
/** @see Output#writeString(String) */
public static class StringSerializer extends ImmutableSerializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, String object) {
output.writeString(object);
}
public String read (Kryo kryo, Input input, Class extends String> type) {
return input.readString();
}
}
/** Serializer for {@link BigInteger} and any subclass.
* @author Tumi (enhacements) */
public static class BigIntegerSerializer extends ImmutableSerializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, BigInteger object) {
if (object == null) {
output.writeByte(NULL);
return;
}
// fast-path optimizations for BigInteger.ZERO constant
if (object == BigInteger.ZERO) {
output.writeByte(2);
output.writeByte(0);
return;
}
// default behaviour
byte[] bytes = object.toByteArray();
output.writeVarInt(bytes.length + 1, true);
output.writeBytes(bytes);
}
public BigInteger read (Kryo kryo, Input input, Class extends BigInteger> type) {
int length = input.readVarInt(true);
if (length == NULL) return null;
byte[] bytes = input.readBytes(length - 1);
if (type != BigInteger.class && type != null) {
// Use reflection for subclasses.
return newBigIntegerSubclass(type, bytes);
}
if (length == 2) {
// Fast-path optimizations for BigInteger constants.
switch (bytes[0]) {
case 0:
return BigInteger.ZERO;
case 1:
return BigInteger.ONE;
case 10:
return BigInteger.TEN;
}
}
return new BigInteger(bytes);
}
private static BigInteger newBigIntegerSubclass(Class extends BigInteger> type, byte[] bytes) {
try {
Constructor extends BigInteger> constructor = type.getConstructor(byte[].class);
if (!constructor.isAccessible()) {
try {
constructor.setAccessible(true);
} catch (SecurityException ignored) {
}
}
return constructor.newInstance(bytes);
} catch (Exception ex) {
throw new KryoException(ex);
}
}
}
/** Serializer for {@link BigDecimal} and any subclass.
* @author Tumi (enhacements) */
public static class BigDecimalSerializer extends ImmutableSerializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, BigDecimal object) {
if (object == null) {
output.writeByte(NULL);
return;
}
if (object == BigDecimal.ZERO) {
output.writeVarInt(2, true);
output.writeByte((byte) 0);
output.writeInt(0, false);
return;
}
if (object == BigDecimal.ONE) {
output.writeVarInt(2, true);
output.writeByte((byte) 1);
output.writeInt(0, false);
return;
}
BigInteger unscaledBig = null; // avoid getting it from BigDecimal, as non-inflated BigDecimal will have to create it
boolean compactForm = object.precision() < 19; // less than nineteen decimal digits for sure fits in a long
if (!compactForm) {
unscaledBig = object.unscaledValue(); // get and remember for possible use in non-compact form
compactForm = unscaledBig.bitLength() <= 63; // check exactly if unscaled value will fit in a long
}
if (!compactForm) {
byte[] bytes = unscaledBig.toByteArray();
output.writeVarInt(bytes.length + 1, true);
output.writeBytes(bytes);
} else {
long unscaledLong = object.scaleByPowerOfTen(object.scale()).longValue(); // best way to get unscaled long value without creating unscaled BigInteger on the way
writeUnscaledLong(output, unscaledLong);
}
output.writeInt(object.scale(), false);
}
// compatible with writing unscaled value represented as BigInteger's bytes
private static void writeUnscaledLong (Output output, long unscaledLong) {
int insignificantBits = unscaledLong >= 0
? numberOfLeadingZeros(unscaledLong)
: numberOfLeadingZeros(~unscaledLong);
int significantBits = (64 - insignificantBits) + 1; // one more bit is for the sign
int length = (significantBits + (8 - 1)) >> 3; // how many bytes are needed (rounded up)
output.writeByte(length + 1);
output.writeLong(unscaledLong, length);
}
public BigDecimal read (Kryo kryo, Input input, Class extends BigDecimal> type) {
BigInteger unscaledBig = null;
long unscaledLong = 0;
int length = input.readVarInt(true);
if (length == NULL) return null;
length--;
if (length > 8) {
byte[] bytes = input.readBytes(length);
unscaledBig = new BigInteger(bytes);
} else {
unscaledLong = input.readLong(length);
}
int scale = input.readInt(false);
if (type != BigDecimal.class && type != null) {
// For subclasses, use reflection
return newBigDecimalSubclass(type, unscaledBig != null ? unscaledBig : BigInteger.valueOf(unscaledLong), scale);
} else {
// For BigDecimal, if possible use factory methods to avoid instantiating BigInteger
if (unscaledBig != null) {
return new BigDecimal(unscaledBig, scale);
} else {
if (scale == 0) {
if (unscaledLong == 0) return BigDecimal.ZERO;
if (unscaledLong == 1) return BigDecimal.ONE;
}
return BigDecimal.valueOf(unscaledLong, scale);
}
}
}
private static BigDecimal newBigDecimalSubclass(Class extends BigDecimal> type, BigInteger unscaledValue, int scale) {
try {
Constructor extends BigDecimal> constructor = type.getConstructor(BigInteger.class, int.class);
if (!constructor.isAccessible()) {
try {
constructor.setAccessible(true);
} catch (SecurityException ignored) {
}
}
return constructor.newInstance(unscaledValue, scale);
} catch (Exception ex) {
throw new KryoException(ex);
}
}
}
public static class ClassSerializer extends ImmutableSerializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, Class type) {
kryo.writeClass(output, type);
if (type != null && (type.isPrimitive() || isWrapperClass(type))) output.writeBoolean(type.isPrimitive());
}
public Class read (Kryo kryo, Input input, Class extends Class> ignored) {
Registration registration = kryo.readClass(input);
if (registration == null) return null;
Class type = registration.getType();
if (!type.isPrimitive() || input.readBoolean()) return type;
return getWrapperClass(type);
}
}
/** Serializer for {@link Date}, {@link java.sql.Date}, {@link Time}, {@link Timestamp} and any other subclass.
* @author Tumi */
public static class DateSerializer extends Serializer {
private Date create (Kryo kryo, Class extends Date> type, long time) throws KryoException {
if (type == Date.class || type == null) {
return new Date(time);
}
if (type == Timestamp.class) {
return new Timestamp(time);
}
if (type == java.sql.Date.class) {
return new java.sql.Date(time);
}
if (type == Time.class) {
return new Time(time);
}
// other cases, reflection
try {
// Try to avoid invoking the no-args constructor
// (which is expected to initialize the instance with the current time)
Constructor extends Date> constructor = type.getConstructor(long.class);
if (!constructor.isAccessible()) {
try {
constructor.setAccessible(true);
} catch (SecurityException ignored) {
}
}
return constructor.newInstance(time);
} catch (Exception ex) {
// default strategy
Date d = kryo.newInstance(type);
d.setTime(time);
return d;
}
}
public void write (Kryo kryo, Output output, Date object) {
output.writeVarLong(object.getTime(), true);
}
public Date read (Kryo kryo, Input input, Class extends Date> type) {
return create(kryo, type, input.readVarLong(true));
}
public Date copy (Kryo kryo, Date original) {
return create(kryo, original.getClass(), original.getTime());
}
}
/** Serializer for {@link Timestamp} which preserves the nanoseconds field. */
public static class TimestampSerializer extends Serializer {
public void write (Kryo kryo, Output output, Timestamp object) {
output.writeVarLong(integralTimeComponent(object), true);
output.writeVarInt(object.getNanos(), true);
}
public Timestamp read (Kryo kryo, Input input, Class extends Timestamp> type) {
return create(input.readVarLong(true), input.readVarInt(true));
}
public Timestamp copy (Kryo kryo, Timestamp original) {
return create(integralTimeComponent(original), original.getNanos());
}
private long integralTimeComponent (Timestamp object) {
return object.getTime() - (object.getNanos() / 1_000_000);
}
private Timestamp create (long time, int nanos) {
Timestamp t = new Timestamp(time);
t.setNanos(nanos);
return t;
}
}
public static class EnumSerializer extends ImmutableSerializer {
{
setAcceptsNull(true);
}
private Object[] enumConstants;
public EnumSerializer (Class extends Enum> type) {
enumConstants = type.getEnumConstants();
// We allow the serialization of the (abstract!) Enum.class (instead of an actual "user" enum),
// which also creates an EnumSerializer instance during Kryo.writeClass with the following trace:
// ClassSerializer.write -> Kryo.writeClass -> DefaultClassResolver.writeClass
// -> Kryo.getDefaultSerializer -> ReflectionSerializerFactory.makeSerializer(kryo, EnumSerializer, Enum.class)
// This EnumSerializer instance is expected to be never called for write/read.
if (enumConstants == null && !Enum.class.equals(type))
throw new IllegalArgumentException("The type must be an enum: " + type);
}
public void write (Kryo kryo, Output output, Enum object) {
if (object == null) {
output.writeVarInt(NULL, true);
return;
}
output.writeVarInt(object.ordinal() + 1, true);
}
public Enum read (Kryo kryo, Input input, Class extends Enum> type) {
int ordinal = input.readVarInt(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;
}
}
public static class EnumSetSerializer extends Serializer {
public void write (Kryo kryo, Output output, EnumSet object) {
Serializer serializer;
if (object.isEmpty()) {
EnumSet tmp = EnumSet.complementOf(object);
if (tmp.isEmpty()) throw new KryoException("An EnumSet must have a defined Enum to be serialized.");
serializer = kryo.writeClass(output, tmp.iterator().next().getClass()).getSerializer();
} else {
serializer = kryo.writeClass(output, object.iterator().next().getClass()).getSerializer();
}
output.writeVarInt(object.size(), true);
for (Object element : object)
serializer.write(kryo, output, element);
}
public EnumSet read (Kryo kryo, Input input, Class extends EnumSet> type) {
Registration registration = kryo.readClass(input);
EnumSet object = EnumSet.noneOf(registration.getType());
Serializer serializer = registration.getSerializer();
int length = input.readVarInt(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 Martin Grotzke */
public static class CurrencySerializer extends ImmutableSerializer {
{
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 extends Currency> type) {
String currencyCode = input.readString();
if (currencyCode == null) return null;
return Currency.getInstance(currencyCode);
}
}
/** @author Martin Grotzke */
public static class StringBufferSerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, StringBuffer object) {
output.writeString(object == null ? null : object.toString());
}
public StringBuffer read (Kryo kryo, Input input, Class extends 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 Martin Grotzke */
public static class StringBuilderSerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, StringBuilder object) {
output.writeString(object == null ? null : object.toString());
}
public StringBuilder read (Kryo kryo, Input input, Class extends StringBuilder> type) {
return input.readStringBuilder();
}
public StringBuilder copy (Kryo kryo, StringBuilder original) {
return new StringBuilder(original);
}
}
public static class KryoSerializableSerializer extends Serializer {
public void write (Kryo kryo, Output output, KryoSerializable object) {
object.write(kryo, output);
}
public KryoSerializable read (Kryo kryo, Input input, Class extends 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 Martin Grotzke */
public static class CollectionsEmptyListSerializer extends ImmutableSerializer {
public void write (Kryo kryo, Output output, Collection object) {
}
public Collection read (Kryo kryo, Input input, Class extends Collection> type) {
return Collections.EMPTY_LIST;
}
}
/** Serializer for maps created via {@link Collections#emptyMap()} or that were just assigned the
* {@link Collections#EMPTY_MAP}.
* @author Martin Grotzke */
public static class CollectionsEmptyMapSerializer extends ImmutableSerializer
© 2015 - 2024 Weber Informatics LLC | Privacy Policy