pax_global_header 0000666 0000000 0000000 00000000064 12105756347 0014524 g ustar 00root root 0000000 0000000 52 comment=928c81e4e20cb237bcc4d71e747409d0b1c86e92
libkryo-java-2.20/ 0000775 0000000 0000000 00000000000 12105756347 0014041 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/ 0000775 0000000 0000000 00000000000 12105756347 0014762 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/.classpath 0000664 0000000 0000000 00000001222 12105756347 0016742 0 ustar 00root root 0000000 0000000
libkryo-java-2.20/java/.project 0000664 0000000 0000000 00000000575 12105756347 0016440 0 ustar 00root root 0000000 0000000
kryo2org.eclipse.jdt.core.javabuilderorg.eclipse.jdt.core.javanature
libkryo-java-2.20/java/.settings/ 0000775 0000000 0000000 00000000000 12105756347 0016700 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/.settings/org.eclipse.jdt.core.prefs 0000664 0000000 0000000 00000015624 12105756347 0023672 0 ustar 00root root 0000000 0000000 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=ignore
org.eclipse.jdt.core.compiler.problem.deprecation=ignore
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled
org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag
org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled
org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=warning
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
org.eclipse.jdt.core.compiler.problem.unusedImport=ignore
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
libkryo-java-2.20/java/license.txt 0000664 0000000 0000000 00000002731 12105756347 0017150 0 ustar 00root root 0000000 0000000 Copyright (c) 2008, 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.
libkryo-java-2.20/java/pom.xml 0000664 0000000 0000000 00000011646 12105756347 0016307 0 ustar 00root root 0000000 0000000 4.0.0org.sonatype.ossoss-parent7com.esotericsoftware.kryokryo2.20-SNAPSHOTjarKryoFast, efficient Java serializationhttp://code.google.com/p/kryo/New BSD Licensehttp://www.opensource.org/licenses/bsd-license.phprepohttp://kryo.googlecode.com/svn/scm:svn:http://kryo.googlecode.com/svn/nathan.sweetNathan Sweetnathan.sweet@gmail.comUTF-8com.esotericsoftware.reflectasmreflectasm1.07shadedcom.esotericsoftware.minlogminlog1.2org.objenesisobjenesis1.2junitjunit4.8.2testsrctestorg.apache.maven.pluginsmaven-compiler-plugintrue1.51.5utf-8maven-resources-plugin2.5default-resourcesnonedefault-testResourcesnoneorg.apache.maven.pluginsmaven-jar-plugin2.4**/.svn/*org.apache.maven.pluginsmaven-shade-plugin1.7trueshadedcom.esotericsoftware.reflectasm:reflectasm:shadedcom.esotericsoftware.minlog:minlogorg.objenesis:objenesisorg.objenesiscom.esotericsoftware.shaded.org.objenesispackageshaderequireSnapshotmaven-enforcer-pluginenforce"${project.version}".endsWith("-SNAPSHOT")Jenkins should only build -SNAPSHOT versionstruesonatype-releasessonatype releases repohttps://oss.sonatype.org/content/repositories/releases
libkryo-java-2.20/java/project.yaml 0000664 0000000 0000000 00000000115 12105756347 0017311 0 ustar 00root root 0000000 0000000 name: kryo
version: 2.20
---
Build.build(project);
Build.oneJAR(project); libkryo-java-2.20/java/src/ 0000775 0000000 0000000 00000000000 12105756347 0015551 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/src/com/ 0000775 0000000 0000000 00000000000 12105756347 0016327 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/src/com/esotericsoftware/ 0000775 0000000 0000000 00000000000 12105756347 0021717 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/src/com/esotericsoftware/kryo/ 0000775 0000000 0000000 00000000000 12105756347 0022703 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/src/com/esotericsoftware/kryo/ClassResolver.java 0000664 0000000 0000000 00000002714 12105756347 0026341 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/** Handles class registration, writing class identifiers to bytes, and reading class identifiers from bytes.
* @author Nathan Sweet */
public interface ClassResolver {
/** Sets the Kryo instance that this ClassResolver will be used for. This is called automatically by Kryo. */
public void setKryo (Kryo kryo);
/** Stores the specified registration.
* @see Kryo#register(Registration) */
public Registration register (Registration registration);
/** Called when an unregistered type is encountered and {@link Kryo#setRegistrationRequired(boolean)} is false. */
public Registration registerImplicit (Class type);
/** Returns the registration for the specified class, or null if the class is not registered. */
public Registration getRegistration (Class type);
/** Returns the registration for the specified ID, or null if no class is registered with that ID. */
public Registration getRegistration (int classID);
/** Writes a class and returns its registration.
* @param type May be null.
* @return Will be null if type is null. */
public Registration writeClass (Output output, Class type);
/** Reads a class and returns its registration.
* @return May be null. */
public Registration readClass (Input input);
/** Called by {@link Kryo#reset()}. */
public void reset ();
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/DefaultSerializer.java 0000664 0000000 0000000 00000001165 12105756347 0027167 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** Sets the default serializer to use for the annotated class. The specified Serializer class must have a constructor taking a
* Kryo instance and a class, a Kryo instance, a class, or no arguments.
* @see Kryo#register(Class)
* @author Nathan Sweet */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DefaultSerializer {
Class extends Serializer> value();
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/Kryo.java 0000664 0000000 0000000 00000136104 12105756347 0024477 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Currency;
import java.util.Date;
import java.util.EnumSet;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;
import org.objenesis.instantiator.ObjectInstantiator;
import org.objenesis.strategy.InstantiatorStrategy;
import org.objenesis.strategy.SerializingInstantiatorStrategy;
import org.objenesis.strategy.StdInstantiatorStrategy;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.CollectionSerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.BooleanArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.ByteArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.CharArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.DoubleArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.FloatArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.IntArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.LongArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.ObjectArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.ShortArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultArraySerializers.StringArraySerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.BigDecimalSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.BigIntegerSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.BooleanSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.ByteSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CalendarSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CharSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.ClassSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CollectionsEmptyListSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CollectionsEmptyMapSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CollectionsEmptySetSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CollectionsSingletonListSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CollectionsSingletonMapSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CollectionsSingletonSetSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.CurrencySerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.DateSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.DoubleSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.EnumSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.EnumSetSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.FloatSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.IntSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.KryoSerializableSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.LongSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.ShortSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.StringBufferSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.StringBuilderSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.StringSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.TimeZoneSerializer;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.TreeMapSerializer;
import com.esotericsoftware.kryo.serializers.FieldSerializer;
import com.esotericsoftware.kryo.serializers.MapSerializer;
import com.esotericsoftware.kryo.util.DefaultClassResolver;
import com.esotericsoftware.kryo.util.IdentityMap;
import com.esotericsoftware.kryo.util.IntArray;
import com.esotericsoftware.kryo.util.MapReferenceResolver;
import com.esotericsoftware.kryo.util.ObjectMap;
import com.esotericsoftware.kryo.util.Util;
import com.esotericsoftware.reflectasm.ConstructorAccess;
import static com.esotericsoftware.kryo.util.Util.*;
import static com.esotericsoftware.minlog.Log.*;
/** Maps classes to serializers so object graphs can be serialized automatically.
* @author Nathan Sweet */
public class Kryo {
static public final byte NULL = 0;
static public final byte NOT_NULL = 1;
static private final int REF = -1;
static private final int NO_REF = -2;
private Class extends Serializer> defaultSerializer = FieldSerializer.class;
private final ArrayList defaultSerializers = new ArrayList(32);
private final int lowPriorityDefaultSerializerCount;
private final ClassResolver classResolver;
private int nextRegisterID;
private Class memoizedClass;
private Registration memoizedClassValue;
private ClassLoader classLoader = getClass().getClassLoader();
private InstantiatorStrategy strategy;
private boolean registrationRequired;
private int depth, maxDepth = Integer.MAX_VALUE;
private boolean autoReset = true;
private volatile Thread thread;
private ObjectMap context, graphContext;
private ReferenceResolver referenceResolver;
private final IntArray readReferenceIds = new IntArray(0);
private boolean references;
private Object readObject;
private int copyDepth;
private boolean copyShallow;
private IdentityMap originalToCopy;
private Object needsCopyReference;
/** Creates a new Kryo with a {@link DefaultClassResolver} and a {@link MapReferenceResolver}. */
public Kryo () {
this(new DefaultClassResolver(), new MapReferenceResolver());
}
/** Creates a new Kryo with a {@link DefaultClassResolver}.
* @param referenceResolver May be null to disable references. */
public Kryo (ReferenceResolver referenceResolver) {
this(new DefaultClassResolver(), referenceResolver);
}
/** @param referenceResolver May be null to disable references. */
public Kryo (ClassResolver classResolver, ReferenceResolver referenceResolver) {
if (classResolver == null) throw new IllegalArgumentException("classResolver cannot be null.");
this.classResolver = classResolver;
classResolver.setKryo(this);
this.referenceResolver = referenceResolver;
if (referenceResolver != null) {
referenceResolver.setKryo(this);
references = true;
}
addDefaultSerializer(byte[].class, ByteArraySerializer.class);
addDefaultSerializer(char[].class, CharArraySerializer.class);
addDefaultSerializer(short[].class, ShortArraySerializer.class);
addDefaultSerializer(int[].class, IntArraySerializer.class);
addDefaultSerializer(long[].class, LongArraySerializer.class);
addDefaultSerializer(float[].class, FloatArraySerializer.class);
addDefaultSerializer(double[].class, DoubleArraySerializer.class);
addDefaultSerializer(boolean[].class, BooleanArraySerializer.class);
addDefaultSerializer(String[].class, StringArraySerializer.class);
addDefaultSerializer(Object[].class, ObjectArraySerializer.class);
addDefaultSerializer(BigInteger.class, BigIntegerSerializer.class);
addDefaultSerializer(BigDecimal.class, BigDecimalSerializer.class);
addDefaultSerializer(Class.class, ClassSerializer.class);
addDefaultSerializer(Date.class, DateSerializer.class);
addDefaultSerializer(Enum.class, EnumSerializer.class);
addDefaultSerializer(EnumSet.class, EnumSetSerializer.class);
addDefaultSerializer(Currency.class, CurrencySerializer.class);
addDefaultSerializer(StringBuffer.class, StringBufferSerializer.class);
addDefaultSerializer(StringBuilder.class, StringBuilderSerializer.class);
addDefaultSerializer(Collections.EMPTY_LIST.getClass(), CollectionsEmptyListSerializer.class);
addDefaultSerializer(Collections.EMPTY_MAP.getClass(), CollectionsEmptyMapSerializer.class);
addDefaultSerializer(Collections.EMPTY_SET.getClass(), CollectionsEmptySetSerializer.class);
addDefaultSerializer(Collections.singletonList(null).getClass(), CollectionsSingletonListSerializer.class);
addDefaultSerializer(Collections.singletonMap(null, null).getClass(), CollectionsSingletonMapSerializer.class);
addDefaultSerializer(Collections.singleton(null).getClass(), CollectionsSingletonSetSerializer.class);
addDefaultSerializer(Collection.class, CollectionSerializer.class);
addDefaultSerializer(TreeMap.class, TreeMapSerializer.class);
addDefaultSerializer(Map.class, MapSerializer.class);
addDefaultSerializer(KryoSerializable.class, KryoSerializableSerializer.class);
addDefaultSerializer(TimeZone.class, TimeZoneSerializer.class);
addDefaultSerializer(Calendar.class, CalendarSerializer.class);
lowPriorityDefaultSerializerCount = defaultSerializers.size();
// Primitives and string. Primitive wrappers automatically use the same registration as primitives.
register(int.class, new IntSerializer());
register(String.class, new StringSerializer());
register(float.class, new FloatSerializer());
register(boolean.class, new BooleanSerializer());
register(byte.class, new ByteSerializer());
register(char.class, new CharSerializer());
register(short.class, new ShortSerializer());
register(long.class, new LongSerializer());
register(double.class, new DoubleSerializer());
}
// --- Default serializers ---
/** Sets the serailzer to use when no {@link #addDefaultSerializer(Class, Class) default serializers} match an object's type.
* Default is {@link FieldSerializer}.
* @see #newDefaultSerializer(Class) */
public void setDefaultSerializer (Class extends Serializer> serializer) {
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
defaultSerializer = serializer;
}
/** Instances of the specified class will use the specified serializer.
* @see #setDefaultSerializer(Class) */
public void addDefaultSerializer (Class type, Serializer serializer) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
DefaultSerializerEntry entry = new DefaultSerializerEntry();
entry.type = type;
entry.serializer = serializer;
defaultSerializers.add(defaultSerializers.size() - lowPriorityDefaultSerializerCount, entry);
}
/** Instances of the specified class will use the specified serializer. Serializer instances are created as needed via
* {@link #newSerializer(Class, Class)}. By default, the following classes have a default serializer set:
*
*
*
*
boolean
*
Boolean
*
byte
*
Byte
*
char
*
*
*
Character
*
short
*
Short
*
int
*
Integer
*
*
*
long
*
Long
*
float
*
Float
*
double
*
*
*
Double
*
String
*
byte[]
*
char[]
*
short[]
*
*
*
int[]
*
long[]
*
float[]
*
double[]
*
String[]
*
*
*
Object[]
*
Map
*
BigInteger
*
BigDecimal
*
KryoSerializable
*
*
*
Collection
*
Date
*
Collections.emptyList
*
Collections.singleton
*
Currency
*
*
*
StringBuilder
*
Enum
*
Collections.emptyMap
*
Collections.emptySet
*
Calendar
*
*
*
StringBuffer
*
Class
*
Collections.singletonList
*
Collections.singletonMap
*
TimeZone
*
*
*
TreeMap
*
EnumSet
*
*
*
* Note that the order default serializers are added is important for a class that may match multiple types. The above default
* serializers always have a lower priority than subsequent default serializers that are added. */
public void addDefaultSerializer (Class type, Class extends Serializer> serializerClass) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (serializerClass == null) throw new IllegalArgumentException("serializerClass cannot be null.");
DefaultSerializerEntry entry = new DefaultSerializerEntry();
entry.type = type;
entry.serializerClass = serializerClass;
defaultSerializers.add(defaultSerializers.size() - lowPriorityDefaultSerializerCount, entry);
}
/** Returns the best matching serializer for a class. This method can be overridden to implement custom logic to choose a
* serializer. */
public Serializer getDefaultSerializer (Class type) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (type.isAnnotationPresent(DefaultSerializer.class))
return newSerializer(((DefaultSerializer)type.getAnnotation(DefaultSerializer.class)).value(), type);
for (int i = 0, n = defaultSerializers.size(); i < n; i++) {
DefaultSerializerEntry entry = defaultSerializers.get(i);
if (entry.type.isAssignableFrom(type)) {
if (entry.serializer != null) return entry.serializer;
return newSerializer(entry.serializerClass, type);
}
}
return newDefaultSerializer(type);
}
/** Called by {@link #getDefaultSerializer(Class)} when no default serializers matched the type. Subclasses can override this
* method to customize behavior. The default implementation calls {@link #newSerializer(Class, Class)} using the
* {@link #setDefaultSerializer(Class) default serializer}. */
protected Serializer newDefaultSerializer (Class type) {
return newSerializer(defaultSerializer, type);
}
/** Creates a new instance of the specified serializer for serializing the specified class. Serializers must have a zero
* argument constructor or one that takes (Kryo), (Class), or (Kryo, Class). */
public Serializer newSerializer (Class extends Serializer> serializerClass, Class type) {
try {
try {
return serializerClass.getConstructor(Kryo.class, Class.class).newInstance(this, type);
} catch (NoSuchMethodException ex1) {
try {
return serializerClass.getConstructor(Kryo.class).newInstance(this);
} catch (NoSuchMethodException ex2) {
try {
return serializerClass.getConstructor(Class.class).newInstance(type);
} catch (NoSuchMethodException ex3) {
return serializerClass.newInstance();
}
}
}
} catch (Exception ex) {
throw new IllegalArgumentException("Unable to create serializer \"" + serializerClass.getName() + "\" for class: "
+ className(type), ex);
}
}
// --- Registration ---
/** Registers the class using the lowest, next available integer ID and the {@link Kryo#getDefaultSerializer(Class) default
* serializer}. If the class is already registered, the existing entry is updated with the new serializer. Registering a
* primitive also affects the corresponding primitive wrapper.
*
* Because the ID assigned is affected by the IDs registered before it, the order classes are registered is important when
* using this method. The order must be the same at deserialization as it was for serialization. */
public Registration register (Class type) {
Registration registration = classResolver.getRegistration(type);
if (registration != null) return registration;
return register(type, getDefaultSerializer(type));
}
/** Registers the class using the specified ID and the {@link Kryo#getDefaultSerializer(Class) default serializer}. If the ID is
* already in use by the same type, the old entry is overwritten. If the ID is already in use by a different type, a
* {@link KryoException} is thrown. Registering a primitive also affects the corresponding primitive wrapper.
*
* IDs must be the same at deserialization as they were for serialization.
* @param id Must be >= 0. Smaller IDs are serialized more efficiently. */
public Registration register (Class type, int id) {
Registration registration = classResolver.getRegistration(type);
if (registration != null) return registration;
return register(type, getDefaultSerializer(type), id);
}
/** Registers the class using the lowest, next available integer ID and the specified serializer. If the class is already
* registered, the existing entry is updated with the new serializer. Registering a primitive also affects the corresponding
* primitive wrapper.
*
* Because the ID assigned is affected by the IDs registered before it, the order classes are registered is important when
* using this method. The order must be the same at deserialization as it was for serialization. */
public Registration register (Class type, Serializer serializer) {
Registration registration = classResolver.getRegistration(type);
if (registration != null) {
registration.setSerializer(serializer);
return registration;
}
return classResolver.register(new Registration(type, serializer, getNextRegistrationId()));
}
/** Registers the class using the specified ID and serializer. If the ID is already in use by the same type, the old entry is
* overwritten. If the ID is already in use by a different type, a {@link KryoException} is thrown. Registering a primitive
* also affects the corresponding primitive wrapper.
*
* IDs must be the same at deserialization as they were for serialization.
* @param id Must be >= 0. Smaller IDs are serialized more efficiently. */
public Registration register (Class type, Serializer serializer, int id) {
if (id < 0) throw new IllegalArgumentException("id must be >= 0: " + id);
return register(new Registration(type, serializer, id));
}
/** Stores the specified registration. If the ID is already in use by the same type, the old entry is overwritten. If the ID is
* already in use by a different type, a {@link KryoException} is thrown. Registering a primitive also affects the
* corresponding primitive wrapper.
*
* IDs must be the same at deserialization as they were for serialization.
*
* Registration can be suclassed to efficiently store per type information, accessible in serializers via
* {@link Kryo#getRegistration(Class)}. */
public Registration register (Registration registration) {
int id = registration.getId();
if (id < 0) throw new IllegalArgumentException("id must be > 0: " + id);
Registration existing = getRegistration(registration.getId());
if (existing != null && existing.getType() != registration.getType()) {
throw new KryoException("An existing registration with a different type already uses ID: " + registration.getId()
+ "\nExisting registration: " + existing + "\nUnable to set registration: " + registration);
}
return classResolver.register(registration);
}
/** Returns the lowest, next available integer ID. */
public int getNextRegistrationId () {
int id = nextRegisterID;
while (true) {
if (classResolver.getRegistration(id) == null) return id;
id++;
}
}
/** @throws IllegalArgumentException if the class is not registered and {@link Kryo#setRegistrationRequired(boolean)} is true.
* @see ClassResolver#getRegistration(Class) */
public Registration getRegistration (Class type) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (type == memoizedClass) return memoizedClassValue;
Registration registration = classResolver.getRegistration(type);
if (registration == null) {
if (Proxy.isProxyClass(type)) {
// If a Proxy class, treat it like an InvocationHandler because the concrete class for a proxy is generated.
registration = getRegistration(InvocationHandler.class);
} else if (!type.isEnum() && Enum.class.isAssignableFrom(type)) {
// This handles an enum value that is an inner class. Eg: enum A {b{}};
registration = getRegistration(type.getEnclosingClass());
} else if (EnumSet.class.isAssignableFrom(type)) {
registration = classResolver.getRegistration(EnumSet.class);
}
if (registration == null) {
if (registrationRequired) {
throw new IllegalArgumentException("Class is not registered: " + className(type)
+ "\nNote: To register this class use: kryo.register(" + className(type) + ".class);");
}
registration = classResolver.registerImplicit(type);
}
}
memoizedClass = type;
memoizedClassValue = registration;
return registration;
}
/** @see ClassResolver#getRegistration(int) */
public Registration getRegistration (int classID) {
return classResolver.getRegistration(classID);
}
/** Returns the serializer for the registration for the specified class.
* @see #getRegistration(Class)
* @see Registration#getSerializer() */
public Serializer getSerializer (Class type) {
return getRegistration(type).getSerializer();
}
// --- Serialization ---
/** Writes a class and returns its registration.
* @param type May be null.
* @return Will be null if type is null.
* @see ClassResolver#writeClass(Output, Class) */
public Registration writeClass (Output output, Class type) {
if (output == null) throw new IllegalArgumentException("output cannot be null.");
try {
return classResolver.writeClass(output, type);
} finally {
if (depth == 0 && autoReset) reset();
}
}
/** Writes an object using the registered serializer. */
public void writeObject (Output output, Object object) {
if (output == null) throw new IllegalArgumentException("output cannot be null.");
if (object == null) throw new IllegalArgumentException("object cannot be null.");
beginObject();
try {
if (references && writeReferenceOrNull(output, object, false)) return;
if (TRACE || (DEBUG && depth == 1)) log("Write", object);
getRegistration(object.getClass()).getSerializer().write(this, output, object);
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Writes an object using the specified serializer. The registered serializer is ignored. */
public void writeObject (Output output, Object object, Serializer serializer) {
if (output == null) throw new IllegalArgumentException("output cannot be null.");
if (object == null) throw new IllegalArgumentException("object cannot be null.");
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
beginObject();
try {
if (references && writeReferenceOrNull(output, object, false)) return;
if (TRACE || (DEBUG && depth == 1)) log("Write", object);
serializer.write(this, output, object);
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Writes an object or null using the registered serializer for the specified type.
* @param object May be null. */
public void writeObjectOrNull (Output output, Object object, Class type) {
if (output == null) throw new IllegalArgumentException("output cannot be null.");
beginObject();
try {
Serializer serializer = getRegistration(type).getSerializer();
if (references) {
if (writeReferenceOrNull(output, object, true)) return;
} else if (!serializer.getAcceptsNull()) {
if (object == null) {
if (TRACE || (DEBUG && depth == 1)) log("Write", object);
output.writeByte(NULL);
return;
}
output.writeByte(NOT_NULL);
}
if (TRACE || (DEBUG && depth == 1)) log("Write", object);
serializer.write(this, output, object);
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Writes an object or null using the specified serializer. The registered serializer is ignored.
* @param object May be null. */
public void writeObjectOrNull (Output output, Object object, Serializer serializer) {
if (output == null) throw new IllegalArgumentException("output cannot be null.");
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
beginObject();
try {
if (references) {
if (writeReferenceOrNull(output, object, true)) return;
} else if (!serializer.getAcceptsNull()) {
if (object == null) {
if (TRACE || (DEBUG && depth == 1)) log("Write", null);
output.writeByte(NULL);
return;
}
output.writeByte(NOT_NULL);
}
if (TRACE || (DEBUG && depth == 1)) log("Write", object);
serializer.write(this, output, object);
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Writes the class and object or null using the registered serializer.
* @param object May be null. */
public void writeClassAndObject (Output output, Object object) {
if (output == null) throw new IllegalArgumentException("output cannot be null.");
beginObject();
try {
if (object == null) {
writeClass(output, null);
return;
}
Registration registration = writeClass(output, object.getClass());
if (references && writeReferenceOrNull(output, object, false)) return;
if (TRACE || (DEBUG && depth == 1)) log("Write", object);
registration.getSerializer().write(this, output, object);
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** @param object May be null if mayBeNull is true.
* @return true if no bytes need to be written for the object. */
boolean writeReferenceOrNull (Output output, Object object, boolean mayBeNull) {
if (object == null) {
if (TRACE || (DEBUG && depth == 1)) log("Write", null);
output.writeByte(Kryo.NULL);
return true;
}
if (!referenceResolver.useReferences(object.getClass())) {
if (mayBeNull) output.writeByte(Kryo.NOT_NULL);
return false;
}
// Determine if this object has already been seen in this object graph.
int id = referenceResolver.getWrittenId(object);
// If not the first time encountered, only write reference ID.
if (id != -1) {
if (DEBUG) debug("kryo", "Write object reference " + id + ": " + string(object));
output.writeInt(id + 2, true); // + 2 because 0 and 1 are used for NULL and NOT_NULL.
return true;
}
// Otherwise write NOT_NULL and then the object bytes.
id = referenceResolver.addWrittenObject(object);
output.writeByte(NOT_NULL);
if (TRACE) trace("kryo", "Write initial object reference " + id + ": " + string(object));
return false;
}
/** Reads a class and returns its registration.
* @return May be null.
* @see ClassResolver#readClass(Input) */
public Registration readClass (Input input) {
if (input == null) throw new IllegalArgumentException("input cannot be null.");
try {
return classResolver.readClass(input);
} finally {
if (depth == 0 && autoReset) reset();
}
}
/** Reads an object using the registered serializer. */
public T readObject (Input input, Class type) {
if (input == null) throw new IllegalArgumentException("input cannot be null.");
if (type == null) throw new IllegalArgumentException("type cannot be null.");
beginObject();
try {
T object;
if (references) {
int stackSize = readReferenceOrNull(input, type, false);
if (stackSize == REF) return (T)readObject;
object = (T)getRegistration(type).getSerializer().read(this, input, type);
if (stackSize == readReferenceIds.size) reference(object);
} else
object = (T)getRegistration(type).getSerializer().read(this, input, type);
if (TRACE || (DEBUG && depth == 1)) log("Read", object);
return object;
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Reads an object using the specified serializer. The registered serializer is ignored. */
public T readObject (Input input, Class type, Serializer serializer) {
if (input == null) throw new IllegalArgumentException("input cannot be null.");
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
beginObject();
try {
T object;
if (references) {
int stackSize = readReferenceOrNull(input, type, false);
if (stackSize == REF) return (T)readObject;
object = (T)serializer.read(this, input, type);
if (stackSize == readReferenceIds.size) reference(object);
} else
object = (T)serializer.read(this, input, type);
if (TRACE || (DEBUG && depth == 1)) log("Read", object);
return object;
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Reads an object or null using the registered serializer.
* @return May be null. */
public T readObjectOrNull (Input input, Class type) {
if (input == null) throw new IllegalArgumentException("input cannot be null.");
if (type == null) throw new IllegalArgumentException("type cannot be null.");
beginObject();
try {
T object;
if (references) {
int stackSize = readReferenceOrNull(input, type, true);
if (stackSize == REF) return (T)readObject;
object = (T)getRegistration(type).getSerializer().read(this, input, type);
if (stackSize == readReferenceIds.size) reference(object);
} else {
Serializer serializer = getRegistration(type).getSerializer();
if (!serializer.getAcceptsNull() && input.readByte() == NULL) {
if (TRACE || (DEBUG && depth == 1)) log("Read", null);
return null;
}
object = (T)serializer.read(this, input, type);
}
if (TRACE || (DEBUG && depth == 1)) log("Read", object);
return object;
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Reads an object or null using the specified serializer. The registered serializer is ignored.
* @return May be null. */
public T readObjectOrNull (Input input, Class type, Serializer serializer) {
if (input == null) throw new IllegalArgumentException("input cannot be null.");
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
beginObject();
try {
T object;
if (references) {
int stackSize = readReferenceOrNull(input, type, true);
if (stackSize == REF) return (T)readObject;
object = (T)serializer.read(this, input, type);
if (stackSize == readReferenceIds.size) reference(object);
} else {
if (!serializer.getAcceptsNull() && input.readByte() == NULL) {
if (TRACE || (DEBUG && depth == 1)) log("Read", null);
return null;
}
object = (T)serializer.read(this, input, type);
}
if (TRACE || (DEBUG && depth == 1)) log("Read", object);
return object;
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Reads the class and object or null using the registered serializer.
* @return May be null. */
public Object readClassAndObject (Input input) {
if (input == null) throw new IllegalArgumentException("input cannot be null.");
beginObject();
try {
Registration registration = readClass(input);
if (registration == null) return null;
Class type = registration.getType();
Object object;
if (references) {
int stackSize = readReferenceOrNull(input, type, false);
if (stackSize == REF) return readObject;
object = registration.getSerializer().read(this, input, type);
if (stackSize == readReferenceIds.size) reference(object);
} else
object = registration.getSerializer().read(this, input, type);
if (TRACE || (DEBUG && depth == 1)) log("Read", object);
return object;
} finally {
if (--depth == 0 && autoReset) reset();
}
}
/** Returns {@link #REF} if a reference to a previously read object was read, which is stored in {@link #readObject}. Returns a
* stack size (> 0) if a reference ID has been put on the stack. */
int readReferenceOrNull (Input input, Class type, boolean mayBeNull) {
if (type.isPrimitive()) type = getWrapperClass(type);
boolean referencesSupported = referenceResolver.useReferences(type);
int id;
if (mayBeNull) {
id = input.readInt(true);
if (id == Kryo.NULL) {
if (TRACE || (DEBUG && depth == 1)) log("Read", null);
readObject = null;
return REF;
}
if (!referencesSupported) {
readReferenceIds.add(NO_REF);
return readReferenceIds.size;
}
} else {
if (!referencesSupported) {
readReferenceIds.add(NO_REF);
return readReferenceIds.size;
}
id = input.readInt(true);
}
if (id == NOT_NULL) {
// First time object has been encountered.
id = referenceResolver.nextReadId(type);
if (TRACE) trace("kryo", "Read initial object reference " + id + ": " + className(type));
readReferenceIds.add(id);
return readReferenceIds.size;
}
// The id is an object reference.
id -= 2; // - 2 because 0 and 1 are used for NULL and NOT_NULL.
readObject = referenceResolver.getReadObject(type, id);
if (DEBUG) debug("kryo", "Read object reference " + id + ": " + string(readObject));
return REF;
}
/** Called by {@link Serializer#read(Kryo, Input, Class)} and {@link Serializer#copy(Kryo, Object)} before Kryo can be used to
* deserialize or copy child objects. Calling this method is unnecessary if Kryo is not used to deserialize or copy child
* objects.
* @param object May be null, unless calling this method from {@link Serializer#copy(Kryo, Object)}. */
public void reference (Object object) {
if (copyDepth > 0) {
if (needsCopyReference != null) {
if (object == null) throw new IllegalArgumentException("object cannot be null.");
originalToCopy.put(needsCopyReference, object);
needsCopyReference = null;
}
} else if (references && object != null) {
int id = readReferenceIds.pop();
if (id != NO_REF) referenceResolver.addReadObject(id, object);
}
}
/** Resets unregistered class names. references to previously serialized or deserialized objects. and the
* {@link #getGraphContext() graph context}. If {@link #setAutoReset(boolean) auto reset} is true, this method is called
* automatically when an object graph has been completely serialized or deserialized. If overridden, the super method must be
* called. */
public void reset () {
depth = 0;
if (graphContext != null) graphContext.clear();
classResolver.reset();
if (references) {
referenceResolver.reset();
readObject = null;
}
copyDepth = 0;
if (originalToCopy != null) originalToCopy.clear();
if (TRACE) trace("kryo", "Object graph complete.");
}
/** Returns a deep copy of the object. Serializers for the classes involved must support {@link Serializer#copy(Kryo, Object)}.
* @param object May be null. */
public T copy (T object) {
if (object == null) return null;
if (copyShallow) return object;
copyDepth++;
try {
if (originalToCopy == null) originalToCopy = new IdentityMap();
Object existingCopy = originalToCopy.get(object);
if (existingCopy != null) return (T)existingCopy;
needsCopyReference = object;
Object copy;
if (object instanceof KryoCopyable)
copy = ((KryoCopyable)object).copy(this);
else
copy = getSerializer(object.getClass()).copy(this, object);
if (needsCopyReference != null) reference(copy);
if (TRACE || (DEBUG && copyDepth == 1)) log("Copy", copy);
return (T)copy;
} finally {
if (--copyDepth == 0) reset();
}
}
/** Returns a deep copy of the object using the specified serializer. Serializers for the classes involved must support
* {@link Serializer#copy(Kryo, Object)}.
* @param object May be null. */
public T copy (T object, Serializer serializer) {
if (object == null) return null;
if (copyShallow) return object;
copyDepth++;
try {
if (originalToCopy == null) originalToCopy = new IdentityMap();
Object existingCopy = originalToCopy.get(object);
if (existingCopy != null) return (T)existingCopy;
needsCopyReference = object;
Object copy;
if (object instanceof KryoCopyable)
copy = ((KryoCopyable)object).copy(this);
else
copy = serializer.copy(this, object);
if (needsCopyReference != null) reference(copy);
if (TRACE || (DEBUG && copyDepth == 1)) log("Copy", copy);
return (T)copy;
} finally {
if (--copyDepth == 0) reset();
}
}
/** Returns a shallow copy of the object. Serializers for the classes involved must support
* {@link Serializer#copy(Kryo, Object)}.
* @param object May be null. */
public T copyShallow (T object) {
if (object == null) return null;
copyDepth++;
copyShallow = true;
try {
if (originalToCopy == null) originalToCopy = new IdentityMap();
Object existingCopy = originalToCopy.get(object);
if (existingCopy != null) return (T)existingCopy;
needsCopyReference = object;
Object copy;
if (object instanceof KryoCopyable)
copy = ((KryoCopyable)object).copy(this);
else
copy = getSerializer(object.getClass()).copy(this, object);
if (needsCopyReference != null) reference(copy);
if (TRACE || (DEBUG && copyDepth == 1)) log("Shallow copy", copy);
return (T)copy;
} finally {
copyShallow = false;
if (--copyDepth == 0) reset();
}
}
/** Returns a shallow copy of the object using the specified serializer. Serializers for the classes involved must support
* {@link Serializer#copy(Kryo, Object)}.
* @param object May be null. */
public T copyShallow (T object, Serializer serializer) {
if (object == null) return null;
copyDepth++;
copyShallow = true;
try {
if (originalToCopy == null) originalToCopy = new IdentityMap();
Object existingCopy = originalToCopy.get(object);
if (existingCopy != null) return (T)existingCopy;
needsCopyReference = object;
Object copy;
if (object instanceof KryoCopyable)
copy = ((KryoCopyable)object).copy(this);
else
copy = serializer.copy(this, object);
if (needsCopyReference != null) reference(copy);
if (TRACE || (DEBUG && copyDepth == 1)) log("Shallow copy", copy);
return (T)copy;
} finally {
copyShallow = false;
if (--copyDepth == 0) reset();
}
}
// --- Utility ---
private void beginObject () {
if (DEBUG) {
if (depth == 0)
thread = Thread.currentThread();
else if (thread != Thread.currentThread())
throw new ConcurrentModificationException("Kryo must not be accessed concurrently by multiple threads.");
}
if (depth == maxDepth) throw new KryoException("Max depth exceeded: " + depth);
depth++;
}
public ClassResolver getClassResolver () {
return classResolver;
}
/** @return May be null. */
public ReferenceResolver getReferenceResolver () {
return referenceResolver;
}
/** Sets the classloader to resolve unregistered class names to classes. The default is the loader that loaded the Kryo class. */
public void setClassLoader (ClassLoader classLoader) {
if (classLoader == null) throw new IllegalArgumentException("classLoader cannot be null.");
this.classLoader = classLoader;
}
public ClassLoader getClassLoader () {
return classLoader;
}
/** If true, an exception is thrown when an unregistered class is encountered. Default is false.
*
* If false, when an unregistered class is encountered, its fully qualified class name will be serialized and the
* {@link #addDefaultSerializer(Class, Class) default serializer} for the class used to serialize the object. Subsequent
* appearances of the class within the same object graph are serialized as an int id.
*
* Registered classes are serialized as an int id, avoiding the overhead of serializing the class name, but have the drawback
* of needing to know the classes to be serialized up front. */
public void setRegistrationRequired (boolean registrationRequired) {
this.registrationRequired = registrationRequired;
if (TRACE) trace("kryo", "Registration required: " + registrationRequired);
}
public boolean isRegistrationRequired () {
return registrationRequired;
}
/** If true, each appearance of an object in the graph after the first is stored as an integer ordinal. When set to true,
* {@link MapReferenceResolver} is used. This enables references to the same object and cyclic graphs to be serialized, but
* typically adds overhead of one byte per object. Default is true.
* @return The previous value. */
public boolean setReferences (boolean references) {
if (references == this.references) return references;
this.references = references;
if (references && referenceResolver == null) referenceResolver = new MapReferenceResolver();
if (TRACE) trace("kryo", "References: " + references);
return !references;
}
/** Sets the reference resolver and enables references. */
public void setReferenceResolver (ReferenceResolver referenceResolver) {
if (referenceResolver == null) throw new IllegalArgumentException("referenceResolver cannot be null.");
this.references = true;
this.referenceResolver = referenceResolver;
if (TRACE) trace("kryo", "Reference resolver: " + referenceResolver.getClass().getName());
}
public boolean getReferences () {
return references;
}
/** Sets the strategy used by {@link #newInstantiator(Class)} for creating objects. See {@link StdInstantiatorStrategy} to
* create objects via without calling any constructor. See {@link SerializingInstantiatorStrategy} to mimic Java's built-in
* serialization.
* @param strategy May be null. */
public void setInstantiatorStrategy (InstantiatorStrategy strategy) {
this.strategy = strategy;
}
/** Returns a new instantiator for creating new instances of the specified type. By default, an instantiator is returned that
* uses reflection if the class has a zero argument constructor, an exception is thrown. If a
* {@link #setInstantiatorStrategy(InstantiatorStrategy) strategy} is set, it will be used instead of throwing an exception. */
protected ObjectInstantiator newInstantiator (final Class type) {
if (!Util.isAndroid) {
// ReflectASM.
try {
final ConstructorAccess access = ConstructorAccess.get(type);
return new ObjectInstantiator() {
public Object newInstance () {
try {
return access.newInstance();
} catch (Exception ex) {
throw new KryoException("Error constructing instance of class: " + className(type), ex);
}
}
};
} catch (Exception ignored) {
}
}
// Reflection.
try {
Constructor ctor;
try {
ctor = type.getConstructor((Class[])null);
} catch (Exception ex) {
ctor = type.getDeclaredConstructor((Class[])null);
ctor.setAccessible(true);
}
final Constructor constructor = ctor;
return new ObjectInstantiator() {
public Object newInstance () {
try {
return constructor.newInstance();
} catch (Exception ex) {
throw new KryoException("Error constructing instance of class: " + className(type), ex);
}
}
};
} catch (Exception ignored) {
}
if (strategy == null) {
if (type.isMemberClass() && !Modifier.isStatic(type.getModifiers()))
throw new KryoException("Class cannot be created (non-static member class): " + className(type));
else
throw new KryoException("Class cannot be created (missing no-arg constructor): " + className(type));
}
// InstantiatorStrategy.
return strategy.newInstantiatorOf(type);
}
/** Creates a new instance of a class using {@link Registration#getInstantiator()}. If the registration's instantiator is null,
* a new one is set using {@link #newInstantiator(Class)}. */
public T newInstance (Class type) {
Registration registration = getRegistration(type);
ObjectInstantiator instantiator = registration.getInstantiator();
if (instantiator == null) {
instantiator = newInstantiator(type);
registration.setInstantiator(instantiator);
}
return (T)instantiator.newInstance();
}
/** Name/value pairs that are available to all serializers. */
public ObjectMap getContext () {
if (context == null) context = new ObjectMap();
return context;
}
/** Name/value pairs that are available to all serializers and are cleared after each object graph is serialized or
* deserialized. */
public ObjectMap getGraphContext () {
if (graphContext == null) graphContext = new ObjectMap();
return graphContext;
}
/** Returns the number of child objects away from the object graph root. */
public int getDepth () {
return depth;
}
/** If true (the default), {@link #reset()} is called automatically after an entire object graph has been read or written. If
* false, {@link #reset()} must be called manually, which allows unregistered class names, references, and other information to
* span multiple object graphs. */
public void setAutoReset (boolean autoReset) {
this.autoReset = autoReset;
}
/** Sets the maxiumum depth of an object graph. This can be used to prevent malicious data from causing a stack overflow.
* Default is {@link Integer#MAX_VALUE}. */
public void setMaxDepth (int maxDepth) {
if (maxDepth <= 0) throw new IllegalArgumentException("maxDepth must be > 0.");
this.maxDepth = maxDepth;
}
/** Returns true if the specified type is final. Final types can be serialized more efficiently because they are
* non-polymorphic.
*
* This can be overridden to force non-final classes to be treated as final. Eg, if an application uses ArrayList extensively
* but never uses an ArrayList subclass, treating ArrayList as final could allow FieldSerializer to save 1-2 bytes per
* ArrayList field. */
public boolean isFinal (Class type) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (type.isArray()) return Modifier.isFinal(Util.getElementClass(type).getModifiers());
return Modifier.isFinal(type.getModifiers());
}
/** Returns the first level of classes or interfaces for a generic type.
* @return null if the specified type is not generic or its generic types are not classes. */
static public Class[] getGenerics (Type genericType) {
if (!(genericType instanceof ParameterizedType)) return null;
Type[] actualTypes = ((ParameterizedType)genericType).getActualTypeArguments();
Class[] generics = new Class[actualTypes.length];
int count = 0;
for (int i = 0, n = actualTypes.length; i < n; i++) {
Type actualType = actualTypes[i];
if (actualType instanceof Class)
generics[i] = (Class)actualType;
else if (actualType instanceof ParameterizedType)
generics[i] = (Class)((ParameterizedType)actualType).getRawType();
else
continue;
count++;
}
if (count == 0) return null;
return generics;
}
static final class DefaultSerializerEntry {
Class type;
Serializer serializer;
Class extends Serializer> serializerClass;
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/KryoCopyable.java 0000664 0000000 0000000 00000001222 12105756347 0026146 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
/** Allows implementing classes to perform their own copying. Hand written copying can be more efficient in some cases.
*
* This method is used instead of the registered serializer {@link Serializer#copy(Kryo, Object)} method.
* @author Nathan Sweet */
public interface KryoCopyable {
/** Returns a copy that has the same values as this object. Before Kryo can be used to copy child objects,
* {@link Kryo#reference(Object)} must be called with the copy to ensure it can be referenced by the child objects.
* @see Serializer#copy(Kryo, Object) */
public T copy (Kryo kryo);
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/KryoException.java 0000664 0000000 0000000 00000002353 12105756347 0026354 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
/** General Kryo RuntimeException.
* @author Nathan Sweet */
public class KryoException extends RuntimeException {
private StringBuffer trace;
public KryoException () {
super();
}
public KryoException (String message, Throwable cause) {
super(message, cause);
}
public KryoException (String message) {
super(message);
}
public KryoException (Throwable cause) {
super(cause);
}
public String getMessage () {
if (trace == null) return super.getMessage();
StringBuffer buffer = new StringBuffer(512);
buffer.append(super.getMessage());
if (buffer.length() > 0) buffer.append('\n');
buffer.append("Serialization trace:");
buffer.append(trace);
return buffer.toString();
}
/** Adds information to the exception message about where in the the object graph serialization failure occurred.
* {@link Serializer Serializers} can catch {@link KryoException}, add trace information, and rethrow the exception. */
public void addTrace (String info) {
if (info == null) throw new IllegalArgumentException("info cannot be null.");
if (trace == null) trace = new StringBuffer(512);
trace.append('\n');
trace.append(info);
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/KryoSerializable.java 0000664 0000000 0000000 00000001276 12105756347 0027027 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.DefaultSerializers.KryoSerializableSerializer;
/** Allows implementing classes to perform their own serialization. Hand written serialization can be more efficient in some cases.
*
* The default serializer for KryoSerializable is {@link KryoSerializableSerializer}, which uses {@link Kryo#newInstance(Class)}
* to construct the class.
* @author Nathan Sweet */
public interface KryoSerializable {
public void write (Kryo kryo, Output output);
public void read (Kryo kryo, Input input);
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/NotNull.java 0000664 0000000 0000000 00000001130 12105756347 0025134 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.esotericsoftware.kryo.serializers.FieldSerializer;
/** Indicates a field can never be null when it is being serialized and deserialized. Some serializers use this to save space. Eg,
* {@link FieldSerializer} may save 1 byte per field.
* @author Nathan Sweet */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface NotNull {
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/ReferenceResolver.java 0000664 0000000 0000000 00000003435 12105756347 0027173 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
/** When references are enabled, this tracks objects that have already been read or written, provides an ID for objects that are
* written, and looks up by ID objects that have been read.
* @author Nathan Sweet */
public interface ReferenceResolver {
/** Sets the Kryo instance that this ClassResolver will be used for. This is called automatically by Kryo. */
public void setKryo (Kryo kryo);
/** Returns an ID for the object if it has been written previously, otherwise returns -1. */
public int getWrittenId (Object object);
/** Returns a new ID for an object that is being written for the first time.
* @return The ID, which is stored more efficiently if it is positive and must not be -1 or -2. */
public int addWrittenObject (Object object);
/** Returns the ID for the next object that will be read. This is called only the first time an object is encountered.
* @param type The type of object that will be read.
* @return The ID, which is stored more efficiently if it is positive and must not be -1 or -2. */
public int nextReadId (Class type);
/** Adds an object that has been read for the first time.
* @param id The ID from {@link #nextReadId(Class)}. */
public void addReadObject (int id, Object object);
/** Returns the object for the specified ID. The ID and object are guaranteed to have been previously passed in a call to
* {@link #addReadObject(int, Object)}. */
public Object getReadObject (Class type, int id);
/** Called by {@link Kryo#reset()}. */
public void reset ();
/** Returns true if references will be written for the specified type.
* @param type Will never be a primitive type, but may be a primitive type wrapper. */
public boolean useReferences (Class type);
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/Registration.java 0000664 0000000 0000000 00000003520 12105756347 0026220 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import org.objenesis.instantiator.ObjectInstantiator;
import static com.esotericsoftware.kryo.util.Util.*;
import static com.esotericsoftware.minlog.Log.*;
/** Describes the {@link Serializer} and class ID to use for a class.
* @author Nathan Sweet */
public class Registration {
private final Class type;
private final int id;
private Serializer serializer;
private ObjectInstantiator instantiator;
public Registration (Class type, Serializer serializer, int id) {
if (type == null) throw new IllegalArgumentException("type cannot be null.");
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
this.type = type;
this.serializer = serializer;
this.id = id;
}
public Class getType () {
return type;
}
/** Returns the registered class ID.
* @see Kryo#register(Class) */
public int getId () {
return id;
}
public Serializer getSerializer () {
return serializer;
}
public void setSerializer (Serializer serializer) {
if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
this.serializer = serializer;
if (TRACE) trace("kryo", "Update registered serializer: " + type.getName() + " (" + serializer.getClass().getName() + ")");
}
/** @return May be null if not yet set. */
public ObjectInstantiator getInstantiator () {
return instantiator;
}
/** Sets the instantiator that will create a new instance of the type in {@link Kryo#newInstance(Class)}. */
public void setInstantiator (ObjectInstantiator instantiator) {
if (instantiator == null) throw new IllegalArgumentException("instantiator cannot be null.");
this.instantiator = instantiator;
}
public String toString () {
return "[" + id + ", " + className(type) + "]";
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/Serializer.java 0000664 0000000 0000000 00000007572 12105756347 0025672 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/** Reads and writes objects to and from bytes.
* @author Nathan Sweet */
public abstract class Serializer {
private boolean acceptsNull, immutable;
public Serializer () {
}
/** @see #setAcceptsNull(boolean) */
public Serializer (boolean acceptsNull) {
this.acceptsNull = acceptsNull;
}
/** @see #setAcceptsNull(boolean)
* @see #setImmutable(boolean) */
public Serializer (boolean acceptsNull, boolean immutable) {
this.acceptsNull = acceptsNull;
this.immutable = immutable;
}
/** Writes the bytes for the object to the output.
*
* This method should not be called directly, instead this serializer can be passed to {@link Kryo} write methods that accept a
* serialier.
* @param object May be null if {@link #getAcceptsNull()} is true. */
abstract public void write (Kryo kryo, Output output, T object);
/** Reads bytes and returns a new object of the specified concrete type.
*
* Before Kryo can be used to read child objects, {@link Kryo#reference(Object)} must be called with the parent object to
* ensure it can be referenced by the child objects. Any serializer that uses {@link Kryo} to read a child object may need to
* be reentrant.
*
* This method should not be called directly, instead this serializer can be passed to {@link Kryo} read methods that accept a
* serialier.
* @return May be null if {@link #getAcceptsNull()} is true. */
abstract public T read (Kryo kryo, Input input, Class type);
public boolean getAcceptsNull () {
return acceptsNull;
}
/** If true, this serializer will handle writing and reading null values. If false, the Kryo framework handles null values and
* the serializer will never receive null.
*
* This can be set to true on a serializer that does not accept nulls if it is known that the serializer will never encounter
* null. Doing this will prevent the framework from writing a byte to denote null. */
public void setAcceptsNull (boolean acceptsNull) {
this.acceptsNull = acceptsNull;
}
public boolean isImmutable () {
return immutable;
}
/** If true, the type this serializer will be used for is considered immutable. This causes {@link #copy(Kryo, Object)} to
* return the original object. */
public void setImmutable (boolean immutable) {
this.immutable = immutable;
}
/** Sets the generic types of the field or method this serializer will be used for on the next call to read or write. Subsequent
* calls to read and write must not use this generic type information. The default implementation does nothing. Subclasses may
* use the information provided to this method for more efficient serialization, eg to use the same type for all items in a
* list.
* @param generics Some (but never all) elements may be null if there is no generic type information at that index. */
public void setGenerics (Kryo kryo, Class[] generics) {
}
/** Returns a copy of the specified object. The default implementation returns the original if {@link #isImmutable()} is true,
* else throws {@link KryoException}. Subclasses should override this method if needed to support {@link Kryo#copy(Object)}.
*
* Before Kryo can be used to copy child objects, {@link Kryo#reference(Object)} must be called with the copy to ensure it can
* be referenced by the child objects. Any serializer that uses {@link Kryo} to copy a child object may need to be reentrant.
*
* This method should not be called directly, instead this serializer can be passed to {@link Kryo} copy methods that accept a
* serialier. */
public T copy (Kryo kryo, T original) {
if (immutable) return original;
throw new KryoException("Serializer does not support copy: " + getClass().getName());
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/ 0000775 0000000 0000000 00000000000 12105756347 0023312 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/ByteBufferInputStream.java 0000664 0000000 0000000 00000002615 12105756347 0030412 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/** An InputStream whose source is a {@link ByteBuffer}.
* @author Nathan Sweet */
public class ByteBufferInputStream extends InputStream {
private ByteBuffer byteBuffer;
public ByteBufferInputStream () {
}
/** Creates a stream with a new non-direct buffer of the specified size. The position and limit of the buffer is zero. */
public ByteBufferInputStream (int bufferSize) {
this(ByteBuffer.allocate(bufferSize));
byteBuffer.flip();
}
/** Creates an uninitialized stream that cannot be used until {@link #setByteBuffer(ByteBuffer)} is called. */
public ByteBufferInputStream (ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
public ByteBuffer getByteBuffer () {
return byteBuffer;
}
public void setByteBuffer (ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
public int read () throws IOException {
if (!byteBuffer.hasRemaining()) return -1;
return byteBuffer.get();
}
public int read (byte[] bytes, int offset, int length) throws IOException {
int count = Math.min(byteBuffer.remaining(), length);
if (count == 0) return -1;
byteBuffer.get(bytes, offset, count);
return count;
}
public int available () throws IOException {
return byteBuffer.remaining();
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/ByteBufferOutputStream.java 0000664 0000000 0000000 00000002527 12105756347 0030615 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
/** An OutputStream whose target is a {@link ByteBuffer}. If bytes would be written that would overflow the buffer,
* {@link #flush()} is called. Subclasses can override flush to empty the buffer.
* @author Nathan Sweet */
public class ByteBufferOutputStream extends OutputStream {
private ByteBuffer byteBuffer;
/** Creates an uninitialized stream that cannot be used until {@link #setByteBuffer(ByteBuffer)} is called. */
public ByteBufferOutputStream () {
}
/** Creates a stream with a new non-direct buffer of the specified size. */
public ByteBufferOutputStream (int bufferSize) {
this(ByteBuffer.allocate(bufferSize));
}
public ByteBufferOutputStream (ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
public ByteBuffer getByteBuffer () {
return byteBuffer;
}
public void setByteBuffer (ByteBuffer byteBuffer) {
this.byteBuffer = byteBuffer;
}
public void write (int b) throws IOException {
if (!byteBuffer.hasRemaining()) flush();
byteBuffer.put((byte)b);
}
public void write (byte[] bytes, int offset, int length) throws IOException {
if (byteBuffer.remaining() < length) flush();
byteBuffer.put(bytes, offset, length);
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/Input.java 0000664 0000000 0000000 00000054226 12105756347 0025265 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.InputStream;
import com.esotericsoftware.kryo.KryoException;
/** An InputStream that reads data from a byte array and optionally fills the byte array from another OutputStream as needed.
* Utility methods are provided for efficiently reading primitive types and strings.
* @author Nathan Sweet */
public class Input extends InputStream {
private byte[] buffer;
private int capacity, position, limit, total;
private char[] chars = new char[32];
private InputStream inputStream;
/** Creates an uninitialized Input. {@link #setBuffer(byte[])} must be called before the Input is used. */
public Input () {
}
/** Creates a new Input for reading from a byte array.
* @param bufferSize The size of the buffer. An exception is thrown if more bytes than this are read. */
public Input (int bufferSize) {
this.capacity = bufferSize;
buffer = new byte[bufferSize];
}
/** Creates a new Input for reading from a byte array.
* @param buffer An exception is thrown if more bytes than this are read. */
public Input (byte[] buffer) {
setBuffer(buffer, 0, buffer.length);
}
/** Creates a new Input for reading from a byte array.
* @param buffer An exception is thrown if more bytes than this are read. */
public Input (byte[] buffer, int offset, int count) {
setBuffer(buffer, offset, count);
}
/** Creates a new Input for reading from an InputStream with a buffer size of 4096. */
public Input (InputStream inputStream) {
this(4096);
if (inputStream == null) throw new IllegalArgumentException("inputStream cannot be null.");
this.inputStream = inputStream;
}
/** Creates a new Input for reading from an InputStream. */
public Input (InputStream inputStream, int bufferSize) {
this(bufferSize);
if (inputStream == null) throw new IllegalArgumentException("inputStream cannot be null.");
this.inputStream = inputStream;
}
/** Sets a new buffer. The position and total are reset, discarding any buffered bytes. */
public void setBuffer (byte[] bytes) {
setBuffer(bytes, 0, bytes.length);
}
/** Sets a new buffer. The position and total are reset, discarding any buffered bytes. */
public void setBuffer (byte[] bytes, int offset, int count) {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
buffer = bytes;
position = offset;
limit = count;
capacity = bytes.length;
total = 0;
inputStream = null;
}
public byte[] getBuffer () {
return buffer;
}
public InputStream getInputStream () {
return inputStream;
}
/** Sets a new InputStream. The position and total are reset, discarding any buffered bytes.
* @param inputStream May be null. */
public void setInputStream (InputStream inputStream) {
this.inputStream = inputStream;
limit = 0;
rewind();
}
/** Returns the number of bytes read. */
public int total () {
return total + position;
}
/** Sets the number of bytes read. */
public void setTotal (int total) {
this.total = total;
}
/** Returns the current position in the buffer. */
public int position () {
return position;
}
/** Sets the current position in the buffer. */
public void setPosition (int position) {
this.position = position;
}
/** Returns the limit for the buffer. */
public int limit () {
return limit;
}
/** Sets the limit in the buffer. */
public void setLimit (int limit) {
this.limit = limit;
}
/** Sets the position and total to zero. */
public void rewind () {
position = 0;
total = 0;
}
/** Discards the specified number of bytes. */
public void skip (int count) throws KryoException {
int skipCount = Math.min(limit - position, count);
while (true) {
position += skipCount;
count -= skipCount;
if (count == 0) break;
skipCount = Math.min(count, capacity);
require(skipCount);
}
}
/** Fills the buffer with more bytes. Can be overridden to fill the bytes from a source other than the InputStream. */
protected int fill (byte[] buffer, int offset, int count) throws KryoException {
if (inputStream == null) return -1;
try {
return inputStream.read(buffer, offset, count);
} catch (IOException ex) {
throw new KryoException(ex);
}
}
/** @param required Must be > 0. The buffer is filled until it has at least this many bytes.
* @return the number of bytes remaining.
* @throws KryoException if EOS is reached before required bytes are read (buffer underflow). */
private int require (int required) throws KryoException {
int remaining = limit - position;
if (remaining >= required) return remaining;
if (required > capacity) throw new KryoException("Buffer too small: capacity: " + capacity + ", required: " + required);
// Compact.
System.arraycopy(buffer, position, buffer, 0, remaining);
total += position;
position = 0;
while (true) {
int count = fill(buffer, remaining, capacity - remaining);
if (count == -1) {
if (remaining >= required) break;
throw new KryoException("Buffer underflow.");
}
remaining += count;
if (remaining >= required) break; // Enough has been read.
}
limit = remaining;
return remaining;
}
/** @param optional Try to fill the buffer with this many bytes.
* @return the number of bytes remaining, but not more than optional, or -1 if the EOS was reached and the buffer is empty. */
private int optional (int optional) throws KryoException {
int remaining = limit - position;
if (remaining >= optional) return optional;
optional = Math.min(optional, capacity);
// Compact.
System.arraycopy(buffer, position, buffer, 0, remaining);
total += position;
position = 0;
while (true) {
int count = fill(buffer, remaining, capacity - remaining);
if (count == -1) break;
remaining += count;
if (remaining >= optional) break; // Enough has been read.
}
limit = remaining;
return remaining == 0 ? -1 : Math.min(remaining, optional);
}
// InputStream
/** Reads a single byte as an int from 0 to 255, or -1 if there are no more bytes are available. */
public int read () throws KryoException {
if (optional(1) == 0) return -1;
return buffer[position++] & 0xFF;
}
/** Reads bytes.length bytes or less and writes them to the specified byte[], starting at 0, and returns the number of bytes
* read. */
public int read (byte[] bytes) throws KryoException {
return read(bytes, 0, bytes.length);
}
/** Reads count bytes or less and writes them to the specified byte[], starting at offset, and returns the number of bytes read
* or -1 if no more bytes are available. */
public int read (byte[] bytes, int offset, int count) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
int startingCount = count;
int copyCount = Math.min(limit - position, count);
while (true) {
System.arraycopy(buffer, position, bytes, offset, copyCount);
position += copyCount;
count -= copyCount;
if (count == 0) break;
offset += copyCount;
copyCount = optional(count);
if (copyCount == -1) {
// End of data.
if (startingCount == count) return -1;
break;
}
if (position == limit) break;
}
return startingCount - count;
}
/** Discards the specified number of bytes. */
public long skip (long count) throws KryoException {
long remaining = count;
while (remaining > 0) {
int skip = Math.max(Integer.MAX_VALUE, (int)remaining);
skip(skip);
remaining -= skip;
}
return count;
}
/** Closes the underlying InputStream, if any. */
public void close () throws KryoException {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ignored) {
}
}
}
// byte
/** Reads a single byte. */
public byte readByte () throws KryoException {
require(1);
return buffer[position++];
}
/** Reads a byte as an int from 0 to 255. */
public int readByteUnsigned () throws KryoException {
require(1);
return buffer[position++] & 0xFF;
}
/** Reads the specified number of bytes into a new byte[]. */
public byte[] readBytes (int length) throws KryoException {
byte[] bytes = new byte[length];
readBytes(bytes, 0, length);
return bytes;
}
/** Reads bytes.length bytes and writes them to the specified byte[], starting at index 0. */
public void readBytes (byte[] bytes) throws KryoException {
readBytes(bytes, 0, bytes.length);
}
/** Reads count bytes and writes them to the specified byte[], starting at offset. */
public void readBytes (byte[] bytes, int offset, int count) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
int copyCount = Math.min(limit - position, count);
while (true) {
System.arraycopy(buffer, position, bytes, offset, copyCount);
position += copyCount;
count -= copyCount;
if (count == 0) break;
offset += copyCount;
copyCount = Math.min(count, capacity);
require(copyCount);
}
}
// int
/** Reads a 4 byte int. */
public int readInt () throws KryoException {
require(4);
byte[] buffer = this.buffer;
int position = this.position;
this.position = position + 4;
return (buffer[position] & 0xFF) << 24 //
| (buffer[position + 1] & 0xFF) << 16 //
| (buffer[position + 2] & 0xFF) << 8 //
| buffer[position + 3] & 0xFF;
}
/** Reads a 1-5 byte int. */
public int readInt (boolean optimizePositive) throws KryoException {
if (require(1) < 5) return readInt_slow(optimizePositive);
int b = buffer[position++];
int result = b & 0x7F;
if ((b & 0x80) != 0) {
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
}
private int readInt_slow (boolean optimizePositive) {
// The buffer is guaranteed to have at least 1 byte.
int b = buffer[position++];
int result = b & 0x7F;
if ((b & 0x80) != 0) {
require(1);
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
}
/** Returns true if enough bytes are available to read an int with {@link #readInt(boolean)}. */
public boolean canReadInt () throws KryoException {
if (limit - position >= 5) return true;
if (optional(5) <= 0) return false;
int p = position;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
return true;
}
/** Returns true if enough bytes are available to read a long with {@link #readLong(boolean)}. */
public boolean canReadLong () throws KryoException {
if (limit - position >= 9) return true;
if (optional(5) <= 0) return false;
int p = position;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
if ((buffer[p++] & 0x80) == 0) return true;
if (p == limit) return false;
return true;
}
// string
/** Reads the length and string of UTF8 characters, or null. This can read strings written by {@link Output#writeString(String)}
* , {@link Output#writeString(CharSequence)}, and {@link Output#writeAscii(String)}.
* @return May be null. */
public String readString () {
int available = require(1);
int b = buffer[position++];
if ((b & 0x80) == 0) return readAscii(); // ASCII.
// Null, empty, or UTF8.
int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b);
switch (charCount) {
case 0:
return null;
case 1:
return "";
}
charCount--;
if (chars.length < charCount) chars = new char[charCount];
readUtf8(charCount);
return new String(chars, 0, charCount);
}
private int readUtf8Length (int b) {
int result = b & 0x3F; // Mask all but first 6 bits.
if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 6;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 13;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 20;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 27;
}
}
}
}
return result;
}
private int readUtf8Length_slow (int b) {
int result = b & 0x3F; // Mask all but first 6 bits.
if ((b & 0x40) != 0) { // Bit 7 means another byte, bit 8 means UTF8.
require(1);
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 6;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 13;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 20;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 27;
}
}
}
}
return result;
}
private void readUtf8 (int charCount) {
byte[] buffer = this.buffer;
char[] chars = this.chars;
// Try to read 7 bit ASCII chars.
int charIndex = 0;
int count = Math.min(require(1), charCount);
int position = this.position;
int b;
while (charIndex < count) {
b = buffer[position++];
if (b < 0) {
position--;
break;
}
chars[charIndex++] = (char)b;
}
this.position = position;
// If buffer didn't hold all chars or any were not ASCII, use slow path for remainder.
if (charIndex < charCount) readUtf8_slow(charCount, charIndex);
}
private void readUtf8_slow (int charCount, int charIndex) {
char[] chars = this.chars;
byte[] buffer = this.buffer;
while (charIndex < charCount) {
if (position == limit) require(1);
int b = buffer[position++] & 0xFF;
switch (b >> 4) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
chars[charIndex] = (char)b;
break;
case 12:
case 13:
if (position == limit) require(1);
chars[charIndex] = (char)((b & 0x1F) << 6 | buffer[position++] & 0x3F);
break;
case 14:
require(2);
chars[charIndex] = (char)((b & 0x0F) << 12 | (buffer[position++] & 0x3F) << 6 | buffer[position++] & 0x3F);
break;
}
charIndex++;
}
}
private String readAscii () {
byte[] buffer = this.buffer;
int end = position;
int start = end - 1;
int limit = this.limit;
int b;
do {
if (end == limit) return readAscii_slow();
b = buffer[end++];
} while ((b & 0x80) == 0);
buffer[end - 1] &= 0x7F; // Mask end of ascii bit.
String value = new String(buffer, 0, start, end - start);
buffer[end - 1] |= 0x80;
position = end;
return value;
}
private String readAscii_slow () {
position--; // Re-read the first byte.
// Copy chars currently in buffer.
int charCount = limit - position;
if (charCount > chars.length) chars = new char[charCount * 2];
char[] chars = this.chars;
byte[] buffer = this.buffer;
for (int i = position, ii = 0, n = limit; i < n; i++, ii++)
chars[ii] = (char)buffer[i];
position = limit;
// Copy additional chars one by one.
while (true) {
require(1);
int b = buffer[position++];
if (charCount == chars.length) {
char[] newChars = new char[charCount * 2];
System.arraycopy(chars, 0, newChars, 0, charCount);
chars = newChars;
this.chars = newChars;
}
if ((b & 0x80) == 0x80) {
chars[charCount++] = (char)(b & 0x7F);
break;
}
chars[charCount++] = (char)b;
}
return new String(chars, 0, charCount);
}
/** Reads the length and string of UTF8 characters, or null. This can read strings written by {@link Output#writeString(String)}
* , {@link Output#writeString(CharSequence)}, and {@link Output#writeAscii(String)}.
* @return May be null. */
public StringBuilder readStringBuilder () {
int available = require(1);
int b = buffer[position++];
if ((b & 0x80) == 0) return new StringBuilder(readAscii()); // ASCII.
// Null, empty, or UTF8.
int charCount = available >= 5 ? readUtf8Length(b) : readUtf8Length_slow(b);
switch (charCount) {
case 0:
return null;
case 1:
return new StringBuilder("");
}
charCount--;
if (chars.length < charCount) chars = new char[charCount];
readUtf8(charCount);
StringBuilder builder = new StringBuilder(charCount);
builder.append(chars, 0, charCount);
return builder;
}
// float
/** Reads a 4 byte float. */
public float readFloat () throws KryoException {
return Float.intBitsToFloat(readInt());
}
/** Reads a 1-5 byte float with reduced precision. */
public float readFloat (float precision, boolean optimizePositive) throws KryoException {
return readInt(optimizePositive) / (float)precision;
}
// short
/** Reads a 2 byte short. */
public short readShort () throws KryoException {
require(2);
return (short)(((buffer[position++] & 0xFF) << 8) | (buffer[position++] & 0xFF));
}
/** Reads a 2 byte short as an int from 0 to 65535. */
public int readShortUnsigned () throws KryoException {
require(2);
return ((buffer[position++] & 0xFF) << 8) | (buffer[position++] & 0xFF);
}
// long
/** Reads an 8 byte long. */
public long readLong () throws KryoException {
require(8);
byte[] buffer = this.buffer;
return (long)buffer[position++] << 56 //
| (long)(buffer[position++] & 0xFF) << 48 //
| (long)(buffer[position++] & 0xFF) << 40 //
| (long)(buffer[position++] & 0xFF) << 32 //
| (long)(buffer[position++] & 0xFF) << 24 //
| (buffer[position++] & 0xFF) << 16 //
| (buffer[position++] & 0xFF) << 8 //
| buffer[position++] & 0xFF;
}
/** Reads a 1-9 byte long. */
public long readLong (boolean optimizePositive) throws KryoException {
if (require(1) < 9) return readLong_slow(optimizePositive);
int b = buffer[position++];
long result = b & 0x7F;
if ((b & 0x80) != 0) {
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
b = buffer[position++];
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) result = (result >>> 1) ^ -(result & 1);
return result;
}
private long readLong_slow (boolean optimizePositive) {
// The buffer is guaranteed to have at least 1 byte.
int b = buffer[position++];
long result = b & 0x7F;
if ((b & 0x80) != 0) {
require(1);
byte[] buffer = this.buffer;
b = buffer[position++];
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (long)(b & 0x7F) << 28;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (long)(b & 0x7F) << 35;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (long)(b & 0x7F) << 42;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (long)(b & 0x7F) << 49;
if ((b & 0x80) != 0) {
require(1);
b = buffer[position++];
result |= (long)b << 56;
}
}
}
}
}
}
}
}
if (!optimizePositive) result = (result >>> 1) ^ -(result & 1);
return result;
}
// boolean
/** Reads a 1 byte boolean. */
public boolean readBoolean () throws KryoException {
require(1);
return buffer[position++] == 1;
}
// char
/** Reads a 2 byte char. */
public char readChar () throws KryoException {
require(2);
return (char)(((buffer[position++] & 0xFF) << 8) | (buffer[position++] & 0xFF));
}
// double
/** Reads an 8 bytes double. */
public double readDouble () throws KryoException {
return Double.longBitsToDouble(readLong());
}
/** Reads a 1-9 byte double with reduced precision. */
public double readDouble (double precision, boolean optimizePositive) throws KryoException {
return readLong(optimizePositive) / (double)precision;
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/InputChunked.java 0000664 0000000 0000000 00000005213 12105756347 0026557 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.InputStream;
import com.esotericsoftware.kryo.KryoException;
import static com.esotericsoftware.minlog.Log.*;
/** An InputStream that reads lengths and chunks of data from another OutputStream, allowing chunks to be skipped.
* @author Nathan Sweet */
public class InputChunked extends Input {
private int chunkSize = -1;
/** Creates an uninitialized InputChunked with a buffer size of 2048. The InputStream must be set before it can be used. */
public InputChunked () {
super(2048);
}
/** Creates an uninitialized InputChunked. The InputStream must be set before it can be used. */
public InputChunked (int bufferSize) {
super(bufferSize);
}
/** Creates an InputChunked with a buffer size of 2048. */
public InputChunked (InputStream inputStream) {
super(inputStream, 2048);
}
public InputChunked (InputStream inputStream, int bufferSize) {
super(inputStream, bufferSize);
}
public void setInputStream (InputStream inputStream) {
super.setInputStream(inputStream);
chunkSize = -1;
}
public void setBuffer (byte[] bytes, int offset, int count) {
super.setBuffer(bytes, offset, count);
chunkSize = -1;
}
public void rewind () {
super.rewind();
chunkSize = -1;
}
protected int fill (byte[] buffer, int offset, int count) throws KryoException {
if (chunkSize == -1) // No current chunk, expect a new chunk.
readChunkSize();
else if (chunkSize == 0) // End of chunks.
return -1;
int actual = super.fill(buffer, offset, Math.min(chunkSize, count));
chunkSize -= actual;
if (chunkSize == 0) readChunkSize(); // Read next chunk size.
return actual;
}
private void readChunkSize () {
try {
InputStream inputStream = getInputStream();
for (int offset = 0, result = 0; offset < 32; offset += 7) {
int b = inputStream.read();
if (b == -1) throw new KryoException("Buffer underflow.");
result |= (b & 0x7F) << offset;
if ((b & 0x80) == 0) {
chunkSize = result;
if (TRACE) trace("kryo", "Read chunk: " + chunkSize);
return;
}
}
} catch (IOException ex) {
throw new KryoException(ex);
}
throw new KryoException("Malformed integer.");
}
/** Advances the stream to the next set of chunks. InputChunked will appear to hit the end of the data until this method is
* called. */
public void nextChunks () {
if (chunkSize == -1) readChunkSize(); // No current chunk, expect a new chunk.
while (chunkSize > 0)
skip(chunkSize);
chunkSize = -1;
if (TRACE) trace("kryo", "Next chunks.");
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/Output.java 0000664 0000000 0000000 00000053652 12105756347 0025470 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.OutputStream;
import com.esotericsoftware.kryo.KryoException;
/** An OutputStream that buffers data in a byte array and optionally flushes to another OutputStream. Utility methods are provided
* for efficiently writing primitive types and strings.
* @author Nathan Sweet */
public class Output extends OutputStream {
private int maxCapacity, capacity, position, total;
private byte[] buffer;
private OutputStream outputStream;
/** Creates an uninitialized Output. {@link #setBuffer(byte[], int)} must be called before the Output is used. */
public Output () {
}
/** Creates a new Output for writing to a byte array.
* @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
public Output (int bufferSize) {
this(bufferSize, bufferSize);
}
/** Creates a new Output for writing to a byte array.
* @param bufferSize The initial size of the buffer.
* @param maxBufferSize The buffer is doubled as needed until it exceeds maxBufferSize and an exception is thrown. */
public Output (int bufferSize, int maxBufferSize) {
if (maxBufferSize < -1) throw new IllegalArgumentException("maxBufferSize cannot be < -1: " + maxBufferSize);
this.capacity = bufferSize;
this.maxCapacity = maxBufferSize == -1 ? Integer.MAX_VALUE : maxBufferSize;
buffer = new byte[bufferSize];
}
/** Creates a new Output for writing to a byte array.
* @see #setBuffer(byte[]) */
public Output (byte[] buffer) {
this(buffer, buffer.length);
}
/** Creates a new Output for writing to a byte array.
* @see #setBuffer(byte[], int) */
public Output (byte[] buffer, int maxBufferSize) {
if (buffer == null) throw new IllegalArgumentException("buffer cannot be null.");
setBuffer(buffer, maxBufferSize);
}
/** Creates a new Output for writing to an OutputStream. A buffer size of 4096 is used. */
public Output (OutputStream outputStream) {
this(4096, 4096);
if (outputStream == null) throw new IllegalArgumentException("outputStream cannot be null.");
this.outputStream = outputStream;
}
/** Creates a new Output for writing to an OutputStream. */
public Output (OutputStream outputStream, int bufferSize) {
this(bufferSize, bufferSize);
if (outputStream == null) throw new IllegalArgumentException("outputStream cannot be null.");
this.outputStream = outputStream;
}
public OutputStream getOutputStream () {
return outputStream;
}
/** Sets a new OutputStream. The position and total are reset, discarding any buffered bytes.
* @param outputStream May be null. */
public void setOutputStream (OutputStream outputStream) {
this.outputStream = outputStream;
position = 0;
total = 0;
}
/** Sets the buffer that will be written to. {@link #setBuffer(byte[], int)} is called with the specified buffer's length as the
* maxBufferSize. */
public void setBuffer (byte[] buffer) {
setBuffer(buffer, buffer.length);
}
/** Sets the buffer that will be written to. The position and total are reset, discarding any buffered bytes. The
* {@link #setOutputStream(OutputStream) OutputStream} is set to null.
* @param maxBufferSize The buffer is doubled as needed until it exceeds maxBufferSize and an exception is thrown. */
public void setBuffer (byte[] buffer, int maxBufferSize) {
if (buffer == null) throw new IllegalArgumentException("buffer cannot be null.");
if (maxBufferSize < -1) throw new IllegalArgumentException("maxBufferSize cannot be < -1: " + maxBufferSize);
this.buffer = buffer;
this.maxCapacity = maxBufferSize == -1 ? Integer.MAX_VALUE : maxBufferSize;
capacity = buffer.length;
position = 0;
total = 0;
outputStream = null;
}
/** Returns the buffer. The bytes between zero and {@link #position()} are the data that has been written. */
public byte[] getBuffer () {
return buffer;
}
/** Returns a new byte array containing the bytes currently in the buffer between zero and {@link #position()}. */
public byte[] toBytes () {
byte[] newBuffer = new byte[position];
System.arraycopy(buffer, 0, newBuffer, 0, position);
return newBuffer;
}
/** Returns the current position in the buffer. This is the number of bytes that have not been flushed. */
public int position () {
return position;
}
/** Sets the current position in the buffer. */
public void setPosition (int position) {
this.position = position;
}
/** Returns the total number of bytes written. This may include bytes that have not been flushed. */
public int total () {
return total + position;
}
/** Sets the position and total to zero. */
public void clear () {
position = 0;
total = 0;
}
/** @return true if the buffer has been resized. */
private boolean require (int required) throws KryoException {
if (capacity - position >= required) return false;
if (required > maxCapacity)
throw new KryoException("Buffer overflow. Max capacity: " + maxCapacity + ", required: " + required);
flush();
while (capacity - position < required) {
if (capacity == maxCapacity)
throw new KryoException("Buffer overflow. Available: " + (capacity - position) + ", required: " + required);
// Grow buffer.
capacity = Math.min(capacity * 2, maxCapacity);
if (capacity < 0) capacity = maxCapacity;
byte[] newBuffer = new byte[capacity];
System.arraycopy(buffer, 0, newBuffer, 0, position);
buffer = newBuffer;
}
return true;
}
// OutputStream
/** Writes the buffered bytes to the underlying OutputStream, if any. */
public void flush () throws KryoException {
if (outputStream == null) return;
try {
outputStream.write(buffer, 0, position);
} catch (IOException ex) {
throw new KryoException(ex);
}
total += position;
position = 0;
}
/** Flushes any buffered bytes and closes the underlying OutputStream, if any. */
public void close () throws KryoException {
flush();
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ignored) {
}
}
}
/** Writes a byte. */
public void write (int value) throws KryoException {
if (position == capacity) require(1);
buffer[position++] = (byte)value;
}
/** Writes the bytes. Note the byte[] length is not written. */
public void write (byte[] bytes) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
writeBytes(bytes, 0, bytes.length);
}
/** Writes the bytes. Note the byte[] length is not written. */
public void write (byte[] bytes, int offset, int length) throws KryoException {
writeBytes(bytes, offset, length);
}
// byte
public void writeByte (byte value) throws KryoException {
if (position == capacity) require(1);
buffer[position++] = value;
}
public void writeByte (int value) throws KryoException {
if (position == capacity) require(1);
buffer[position++] = (byte)value;
}
/** Writes the bytes. Note the byte[] length is not written. */
public void writeBytes (byte[] bytes) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
writeBytes(bytes, 0, bytes.length);
}
/** Writes the bytes. Note the byte[] length is not written. */
public void writeBytes (byte[] bytes, int offset, int count) throws KryoException {
if (bytes == null) throw new IllegalArgumentException("bytes cannot be null.");
int copyCount = Math.min(capacity - position, count);
while (true) {
System.arraycopy(bytes, offset, buffer, position, copyCount);
position += copyCount;
count -= copyCount;
if (count == 0) return;
offset += copyCount;
copyCount = Math.min(capacity, count);
require(copyCount);
}
}
// int
/** Writes a 4 byte int. */
public void writeInt (int value) throws KryoException {
require(4);
byte[] buffer = this.buffer;
buffer[position++] = (byte)(value >> 24);
buffer[position++] = (byte)(value >> 16);
buffer[position++] = (byte)(value >> 8);
buffer[position++] = (byte)value;
}
/** Writes a 1-5 byte int.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (5 bytes). */
public int writeInt (int value, boolean optimizePositive) throws KryoException {
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
if (value >>> 7 == 0) {
require(1);
buffer[position++] = (byte)value;
return 1;
}
if (value >>> 14 == 0) {
require(2);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7);
return 2;
}
if (value >>> 21 == 0) {
require(3);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14);
return 3;
}
if (value >>> 28 == 0) {
require(4);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21);
return 4;
}
require(5);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28);
return 5;
}
// string
/** Writes the length and string, or null. Short strings are checked and if ASCII they are written more efficiently, else they
* are written as UTF8. If a string is known to be ASCII, {@link #writeAscii(String)} may be used. The string can be read using
* {@link Input#readString()} or {@link Input#readStringBuilder()}.
* @param value May be null. */
public void writeString (String value) throws KryoException {
if (value == null) {
writeByte(0x80); // 0 means null, bit 8 means UTF8.
return;
}
int charCount = value.length();
if (charCount == 0) {
writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8.
return;
}
// Detect ASCII.
boolean ascii = false;
if (charCount > 1 && charCount < 64) {
ascii = true;
for (int i = 0; i < charCount; i++) {
int c = value.charAt(i);
if (c > 127) {
ascii = false;
break;
}
}
}
if (ascii) {
if (capacity - position < charCount)
writeAscii_slow(value, charCount);
else {
value.getBytes(0, charCount, buffer, position);
position += charCount;
}
buffer[position - 1] |= 0x80;
} else {
writeUtf8Length(charCount + 1);
int charIndex = 0;
if (capacity - position >= charCount) {
// Try to write 8 bit chars.
byte[] buffer = this.buffer;
int position = this.position;
for (; charIndex < charCount; charIndex++) {
int c = value.charAt(charIndex);
if (c > 127) break;
buffer[position++] = (byte)c;
}
this.position = position;
}
if (charIndex < charCount) writeString_slow(value, charCount, charIndex);
}
}
/** Writes the length and CharSequence as UTF8, or null. The string can be read using {@link Input#readString()} or
* {@link Input#readStringBuilder()}.
* @param value May be null. */
public void writeString (CharSequence value) throws KryoException {
if (value == null) {
writeByte(0x80); // 0 means null, bit 8 means UTF8.
return;
}
int charCount = value.length();
if (charCount == 0) {
writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8.
return;
}
writeUtf8Length(charCount + 1);
int charIndex = 0;
if (capacity - position >= charCount) {
// Try to write 8 bit chars.
byte[] buffer = this.buffer;
int position = this.position;
for (; charIndex < charCount; charIndex++) {
int c = value.charAt(charIndex);
if (c > 127) break;
buffer[position++] = (byte)c;
}
this.position = position;
}
if (charIndex < charCount) writeString_slow(value, charCount, charIndex);
}
/** Writes a string that is known to contain only ASCII characters. Non-ASCII strings passed to this method will be corrupted.
* Each byte is a 7 bit character with the remaining byte denoting if another character is available. This is slightly more
* efficient than {@link #writeString(String)}. The string can be read using {@link Input#readString()} or
* {@link Input#readStringBuilder()}.
* @param value May be null. */
public void writeAscii (String value) throws KryoException {
if (value == null) {
writeByte(0x80); // 0 means null, bit 8 means UTF8.
return;
}
int charCount = value.length();
if (charCount == 0) {
writeByte(1 | 0x80); // 1 means empty string, bit 8 means UTF8.
return;
}
if (capacity - position < charCount)
writeAscii_slow(value, charCount);
else {
value.getBytes(0, charCount, buffer, position);
position += charCount;
}
buffer[position - 1] |= 0x80; // Bit 8 means end of ASCII.
}
/** Writes the length of a string, which is a variable length encoded int except the first byte uses bit 8 to denote UTF8 and
* bit 7 to denote if another byte is present. */
private void writeUtf8Length (int value) {
if (value >>> 6 == 0) {
require(1);
buffer[position++] = (byte)(value | 0x80); // Set bit 8.
} else if (value >>> 13 == 0) {
require(2);
byte[] buffer = this.buffer;
buffer[position++] = (byte)(value | 0x40 | 0x80); // Set bit 7 and 8.
buffer[position++] = (byte)(value >>> 6);
} else if (value >>> 20 == 0) {
require(3);
byte[] buffer = this.buffer;
buffer[position++] = (byte)(value | 0x40 | 0x80); // Set bit 7 and 8.
buffer[position++] = (byte)((value >>> 6) | 0x80); // Set bit 8.
buffer[position++] = (byte)(value >>> 13);
} else if (value >>> 27 == 0) {
require(4);
byte[] buffer = this.buffer;
buffer[position++] = (byte)(value | 0x40 | 0x80); // Set bit 7 and 8.
buffer[position++] = (byte)((value >>> 6) | 0x80); // Set bit 8.
buffer[position++] = (byte)((value >>> 13) | 0x80); // Set bit 8.
buffer[position++] = (byte)(value >>> 20);
} else {
require(5);
byte[] buffer = this.buffer;
buffer[position++] = (byte)(value | 0x40 | 0x80); // Set bit 7 and 8.
buffer[position++] = (byte)((value >>> 6) | 0x80); // Set bit 8.
buffer[position++] = (byte)((value >>> 13) | 0x80); // Set bit 8.
buffer[position++] = (byte)((value >>> 20) | 0x80); // Set bit 8.
buffer[position++] = (byte)(value >>> 27);
}
}
private void writeString_slow (CharSequence value, int charCount, int charIndex) {
for (; charIndex < charCount; charIndex++) {
if (position == capacity) require(Math.min(capacity, charCount - charIndex));
int c = value.charAt(charIndex);
if (c <= 0x007F) {
buffer[position++] = (byte)c;
} else if (c > 0x07FF) {
buffer[position++] = (byte)(0xE0 | c >> 12 & 0x0F);
require(2);
buffer[position++] = (byte)(0x80 | c >> 6 & 0x3F);
buffer[position++] = (byte)(0x80 | c & 0x3F);
} else {
buffer[position++] = (byte)(0xC0 | c >> 6 & 0x1F);
require(1);
buffer[position++] = (byte)(0x80 | c & 0x3F);
}
}
}
private void writeAscii_slow (String value, int charCount) throws KryoException {
byte[] buffer = this.buffer;
int charIndex = 0;
int charsToWrite = Math.min(charCount, capacity - position);
while (charIndex < charCount) {
value.getBytes(charIndex, charIndex + charsToWrite, buffer, position);
charIndex += charsToWrite;
position += charsToWrite;
charsToWrite = Math.min(charCount - charIndex, capacity);
if (require(charsToWrite)) buffer = this.buffer;
}
}
// float
/** Writes a 4 byte float. */
public void writeFloat (float value) throws KryoException {
writeInt(Float.floatToIntBits(value));
}
/** Writes a 1-5 byte float with reduced precision.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (5 bytes). */
public int writeFloat (float value, float precision, boolean optimizePositive) throws KryoException {
return writeInt((int)(value * precision), optimizePositive);
}
// short
/** Writes a 2 byte short. */
public void writeShort (int value) throws KryoException {
require(2);
buffer[position++] = (byte)(value >>> 8);
buffer[position++] = (byte)value;
}
// long
/** Writes an 8 byte long. */
public void writeLong (long value) throws KryoException {
require(8);
byte[] buffer = this.buffer;
buffer[position++] = (byte)(value >>> 56);
buffer[position++] = (byte)(value >>> 48);
buffer[position++] = (byte)(value >>> 40);
buffer[position++] = (byte)(value >>> 32);
buffer[position++] = (byte)(value >>> 24);
buffer[position++] = (byte)(value >>> 16);
buffer[position++] = (byte)(value >>> 8);
buffer[position++] = (byte)value;
}
/** Writes a 1-9 byte long.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes). */
public int writeLong (long value, boolean optimizePositive) throws KryoException {
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
if (value >>> 7 == 0) {
require(1);
buffer[position++] = (byte)value;
return 1;
}
if (value >>> 14 == 0) {
require(2);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7);
return 2;
}
if (value >>> 21 == 0) {
require(3);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14);
return 3;
}
if (value >>> 28 == 0) {
require(4);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21);
return 4;
}
if (value >>> 35 == 0) {
require(5);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28);
return 5;
}
if (value >>> 42 == 0) {
require(6);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28 | 0x80);
buffer[position++] = (byte)(value >>> 35);
return 6;
}
if (value >>> 49 == 0) {
require(7);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28 | 0x80);
buffer[position++] = (byte)(value >>> 35 | 0x80);
buffer[position++] = (byte)(value >>> 42);
return 7;
}
if (value >>> 56 == 0) {
require(8);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28 | 0x80);
buffer[position++] = (byte)(value >>> 35 | 0x80);
buffer[position++] = (byte)(value >>> 42 | 0x80);
buffer[position++] = (byte)(value >>> 49);
return 8;
}
require(9);
buffer[position++] = (byte)((value & 0x7F) | 0x80);
buffer[position++] = (byte)(value >>> 7 | 0x80);
buffer[position++] = (byte)(value >>> 14 | 0x80);
buffer[position++] = (byte)(value >>> 21 | 0x80);
buffer[position++] = (byte)(value >>> 28 | 0x80);
buffer[position++] = (byte)(value >>> 35 | 0x80);
buffer[position++] = (byte)(value >>> 42 | 0x80);
buffer[position++] = (byte)(value >>> 49 | 0x80);
buffer[position++] = (byte)(value >>> 56);
return 9;
}
// boolean
/** Writes a 1 byte boolean. */
public void writeBoolean (boolean value) throws KryoException {
require(1);
buffer[position++] = (byte)(value ? 1 : 0);
}
// char
/** Writes a 2 byte char. */
public void writeChar (char value) throws KryoException {
require(2);
buffer[position++] = (byte)(value >>> 8);
buffer[position++] = (byte)value;
}
// double
/** Writes an 8 byte double. */
public void writeDouble (double value) throws KryoException {
writeLong(Double.doubleToLongBits(value));
}
/** Writes a 1-9 byte double with reduced precision.
* @param optimizePositive If true, small positive numbers will be more efficient (1 byte) and small negative numbers will be
* inefficient (9 bytes). */
public int writeDouble (double value, double precision, boolean optimizePositive) throws KryoException {
return writeLong((long)(value * precision), optimizePositive);
}
/** Returns the number of bytes that would be written with {@link #writeInt(int, boolean)}. */
static public int intLength (int value, boolean optimizePositive) {
if (!optimizePositive) value = (value << 1) ^ (value >> 31);
if (value >>> 7 == 0) return 1;
if (value >>> 14 == 0) return 2;
if (value >>> 21 == 0) return 3;
if (value >>> 28 == 0) return 4;
return 5;
}
/** Returns the number of bytes that would be written with {@link #writeLong(long, boolean)}. */
static public int longLength (long value, boolean optimizePositive) {
if (!optimizePositive) value = (value << 1) ^ (value >> 63);
if (value >>> 7 == 0) return 1;
if (value >>> 14 == 0) return 2;
if (value >>> 21 == 0) return 3;
if (value >>> 28 == 0) return 4;
if (value >>> 35 == 0) return 5;
if (value >>> 42 == 0) return 6;
if (value >>> 49 == 0) return 7;
if (value >>> 56 == 0) return 8;
return 9;
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/io/OutputChunked.java 0000664 0000000 0000000 00000005036 12105756347 0026763 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.OutputStream;
import com.esotericsoftware.kryo.KryoException;
import static com.esotericsoftware.minlog.Log.*;
/** An OutputStream that buffers data in a byte array and flushes to another OutputStream, writing the length before each flush.
* The length allows the chunks to be skipped when reading.
* @author Nathan Sweet */
public class OutputChunked extends Output {
/** Creates an uninitialized OutputChunked with a maximum chunk size of 2048. The OutputStream must be set before it can be
* used. */
public OutputChunked () {
super(2048);
}
/** Creates an uninitialized OutputChunked. The OutputStream must be set before it can be used.
* @param bufferSize The maximum size of a chunk. */
public OutputChunked (int bufferSize) {
super(bufferSize);
}
/** Creates an OutputChunked with a maximum chunk size of 2048. */
public OutputChunked (OutputStream outputStream) {
super(outputStream, 2048);
}
/** @param bufferSize The maximum size of a chunk. */
public OutputChunked (OutputStream outputStream, int bufferSize) {
super(outputStream, bufferSize);
}
public void flush () throws KryoException {
if (position() > 0) {
try {
writeChunkSize();
} catch (IOException ex) {
throw new KryoException(ex);
}
}
super.flush();
}
private void writeChunkSize () throws IOException {
int size = position();
if (TRACE) trace("kryo", "Write chunk: " + size);
OutputStream outputStream = getOutputStream();
if ((size & ~0x7F) == 0) {
outputStream.write(size);
return;
}
outputStream.write((size & 0x7F) | 0x80);
size >>>= 7;
if ((size & ~0x7F) == 0) {
outputStream.write(size);
return;
}
outputStream.write((size & 0x7F) | 0x80);
size >>>= 7;
if ((size & ~0x7F) == 0) {
outputStream.write(size);
return;
}
outputStream.write((size & 0x7F) | 0x80);
size >>>= 7;
if ((size & ~0x7F) == 0) {
outputStream.write(size);
return;
}
outputStream.write((size & 0x7F) | 0x80);
size >>>= 7;
outputStream.write(size);
}
/** Marks the end of some data that may have been written by any number of chunks. These chunks can then be skipped when
* reading. */
public void endChunks () {
flush(); // Flush any partial chunk.
if (TRACE) trace("kryo", "End chunks.");
try {
getOutputStream().write(0); // Zero length chunk.
} catch (IOException ex) {
throw new KryoException(ex);
}
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/serializers/ 0000775 0000000 0000000 00000000000 12105756347 0025237 5 ustar 00root root 0000000 0000000 libkryo-java-2.20/java/src/com/esotericsoftware/kryo/serializers/BeanSerializer.java 0000664 0000000 0000000 00000016675 12105756347 0031020 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.serializers;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.reflectasm.MethodAccess;
import static com.esotericsoftware.minlog.Log.*;
/** Serializes Java beans using bean accessor methods. Only bean properties with both a getter and setter are serialized. This
* class is not as fast as {@link FieldSerializer} but is much faster and more efficient than Java serialization. Bytecode
* generation is used to invoke the bean propert methods, if possible.
*
* BeanSerializer does not write header data, only the object data is stored. If the type of a bean property is not final (note
* primitives are final) then an extra byte is written for that property.
* @see Serializer
* @see Kryo#register(Class, Serializer)
* @author Nathan Sweet */
public class BeanSerializer extends Serializer {
static final Object[] noArgs = {};
private final Kryo kryo;
private CachedProperty[] properties;
Object access;
public BeanSerializer (Kryo kryo, Class type) {
this.kryo = kryo;
BeanInfo info;
try {
info = Introspector.getBeanInfo(type);
} catch (IntrospectionException ex) {
throw new KryoException("Error getting bean info.", ex);
}
// Methods are sorted by alpha so the order of the data is known.
PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
Arrays.sort(descriptors, new Comparator() {
public int compare (PropertyDescriptor o1, PropertyDescriptor o2) {
return o1.getName().compareTo(o2.getName());
}
});
ArrayList cachedProperties = new ArrayList(descriptors.length);
for (int i = 0, n = descriptors.length; i < n; i++) {
PropertyDescriptor property = descriptors[i];
String name = property.getName();
if (name.equals("class")) continue;
Method getMethod = property.getReadMethod();
Method setMethod = property.getWriteMethod();
if (getMethod == null || setMethod == null) continue; // Require both a getter and setter.
// Always use the same serializer for this property if the properties' class is final.
Serializer serializer = null;
Class returnType = getMethod.getReturnType();
if (kryo.isFinal(returnType)) serializer = kryo.getRegistration(returnType).getSerializer();
CachedProperty cachedProperty = new CachedProperty();
cachedProperty.name = name;
cachedProperty.getMethod = getMethod;
cachedProperty.setMethod = setMethod;
cachedProperty.serializer = serializer;
cachedProperty.setMethodType = setMethod.getParameterTypes()[0];
cachedProperties.add(cachedProperty);
}
properties = cachedProperties.toArray(new CachedProperty[cachedProperties.size()]);
try {
access = MethodAccess.get(type);
for (int i = 0, n = properties.length; i < n; i++) {
CachedProperty property = properties[i];
property.getterAccessIndex = ((MethodAccess)access).getIndex(property.getMethod.getName());
property.setterAccessIndex = ((MethodAccess)access).getIndex(property.setMethod.getName());
}
} catch (Throwable ignored) {
// ReflectASM is not available on Android.
}
}
public void write (Kryo kryo, Output output, T object) {
Class type = object.getClass();
for (int i = 0, n = properties.length; i < n; i++) {
CachedProperty property = properties[i];
try {
if (TRACE) trace("kryo", "Write property: " + property + " (" + type.getName() + ")");
Object value = property.get(object);
Serializer serializer = property.serializer;
if (serializer != null)
kryo.writeObjectOrNull(output, value, serializer);
else
kryo.writeClassAndObject(output, value);
} catch (IllegalAccessException ex) {
throw new KryoException("Error accessing getter method: " + property + " (" + type.getName() + ")", ex);
} catch (InvocationTargetException ex) {
throw new KryoException("Error invoking getter method: " + property + " (" + type.getName() + ")", ex);
} catch (KryoException ex) {
ex.addTrace(property + " (" + type.getName() + ")");
throw ex;
} catch (RuntimeException runtimeEx) {
KryoException ex = new KryoException(runtimeEx);
ex.addTrace(property + " (" + type.getName() + ")");
throw ex;
}
}
}
public T read (Kryo kryo, Input input, Class type) {
T object = kryo.newInstance(type);
kryo.reference(object);
for (int i = 0, n = properties.length; i < n; i++) {
CachedProperty property = properties[i];
try {
if (TRACE) trace("kryo", "Read property: " + property + " (" + object.getClass() + ")");
Object value;
Serializer serializer = property.serializer;
if (serializer != null)
value = kryo.readObjectOrNull(input, property.setMethodType, serializer);
else
value = kryo.readClassAndObject(input);
property.set(object, value);
} catch (IllegalAccessException ex) {
throw new KryoException("Error accessing setter method: " + property + " (" + object.getClass().getName() + ")", ex);
} catch (InvocationTargetException ex) {
throw new KryoException("Error invoking setter method: " + property + " (" + object.getClass().getName() + ")", ex);
} catch (KryoException ex) {
ex.addTrace(property + " (" + object.getClass().getName() + ")");
throw ex;
} catch (RuntimeException runtimeEx) {
KryoException ex = new KryoException(runtimeEx);
ex.addTrace(property + " (" + object.getClass().getName() + ")");
throw ex;
}
}
return object;
}
public T copy (Kryo kryo, T original) {
T copy = (T)kryo.newInstance(original.getClass());
for (int i = 0, n = properties.length; i < n; i++) {
CachedProperty property = properties[i];
try {
Object value = property.get(original);
property.set(copy, value);
} catch (KryoException ex) {
ex.addTrace(property + " (" + copy.getClass().getName() + ")");
throw ex;
} catch (RuntimeException runtimeEx) {
KryoException ex = new KryoException(runtimeEx);
ex.addTrace(property + " (" + copy.getClass().getName() + ")");
throw ex;
} catch (Exception ex) {
throw new KryoException("Error copying bean property: " + property + " (" + copy.getClass().getName() + ")", ex);
}
}
return copy;
}
class CachedProperty {
String name;
Method getMethod, setMethod;
Class setMethodType;
Serializer serializer;
int getterAccessIndex, setterAccessIndex;
public String toString () {
return name;
}
Object get (Object object) throws IllegalAccessException, InvocationTargetException {
if (access != null) return ((MethodAccess)access).invoke(object, getterAccessIndex);
return getMethod.invoke(object, noArgs);
}
void set (Object object, Object value) throws IllegalAccessException, InvocationTargetException {
if (access != null) {
((MethodAccess)access).invoke(object, setterAccessIndex, value);
return;
}
setMethod.invoke(object, new Object[] {value});
}
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/serializers/BlowfishSerializer.java 0000664 0000000 0000000 00000003720 12105756347 0031713 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.serializers;
import java.io.IOException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/** Encrypts data using the blowfish cipher.
* @author Nathan Sweet */
public class BlowfishSerializer extends Serializer {
private final Serializer serializer;
static private SecretKeySpec keySpec;
public BlowfishSerializer (Serializer serializer, byte[] key) {
this.serializer = serializer;
keySpec = new SecretKeySpec(key, "Blowfish");
}
public void write (Kryo kryo, Output output, Object object) {
Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
CipherOutputStream cipherStream = new CipherOutputStream(output, cipher);
Output cipherOutput = new Output(cipherStream, 256) {
public void close () throws KryoException {
// Don't allow the CipherOutputStream to close the output.
}
};
kryo.writeObject(cipherOutput, object, serializer);
cipherOutput.flush();
try {
cipherStream.close();
} catch (IOException ex) {
throw new KryoException(ex);
}
}
public Object read (Kryo kryo, Input input, Class type) {
Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
CipherInputStream cipherInput = new CipherInputStream(input, cipher);
return kryo.readObject(new Input(cipherInput, 256), type, serializer);
}
public Object copy (Kryo kryo, Object original) {
return serializer.copy(kryo, original);
}
static private Cipher getCipher (int mode) {
try {
Cipher cipher = Cipher.getInstance("Blowfish");
cipher.init(mode, keySpec);
return cipher;
} catch (Exception ex) {
throw new KryoException(ex);
}
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/serializers/CollectionSerializer.java 0000664 0000000 0000000 00000011366 12105756347 0032236 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.serializers;
import java.util.ArrayList;
import java.util.Collection;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/** Serializes objects that implement the {@link Collection} interface.
*
* With the default constructor, a collection requires a 1-3 byte header and an extra 2-3 bytes is written for each element in the
* collection. The alternate constructor can be used to improve efficiency to match that of using an array instead of a
* collection.
* @author Nathan Sweet */
public class CollectionSerializer extends Serializer {
private boolean elementsCanBeNull = true;
private Serializer serializer;
private Class elementClass;
private Class genericType;
public CollectionSerializer () {
}
/** @see #setElementClass(Class, Serializer) */
public CollectionSerializer (Class elementClass, Serializer serializer) {
setElementClass(elementClass, serializer);
}
/** @see #setElementClass(Class, Serializer)
* @see #setElementsCanBeNull(boolean) */
public CollectionSerializer (Class elementClass, Serializer serializer, boolean elementsCanBeNull) {
setElementClass(elementClass, serializer);
this.elementsCanBeNull = elementsCanBeNull;
}
/** @param elementsCanBeNull False if all elements are not null. This saves 1 byte per element if elementClass is set. True if it
* is not known (default). */
public void setElementsCanBeNull (boolean elementsCanBeNull) {
this.elementsCanBeNull = elementsCanBeNull;
}
/** @param elementClass The concrete class of each element. This saves 1-2 bytes per element. Set to null if the class is not
* known or varies per element (default).
* @param serializer The serializer to use for each element. */
public void setElementClass (Class elementClass, Serializer serializer) {
this.elementClass = elementClass;
this.serializer = serializer;
}
public void setGenerics (Kryo kryo, Class[] generics) {
if (kryo.isFinal(generics[0])) genericType = generics[0];
}
public void write (Kryo kryo, Output output, Collection collection) {
int length = collection.size();
output.writeInt(length, true);
Serializer serializer = this.serializer;
if (genericType != null) {
if (serializer == null) serializer = kryo.getSerializer(genericType);
genericType = null;
}
if (serializer != null) {
if (elementsCanBeNull) {
for (Object element : collection)
kryo.writeObjectOrNull(output, element, serializer);
} else {
for (Object element : collection)
kryo.writeObject(output, element, serializer);
}
} else {
for (Object element : collection)
kryo.writeClassAndObject(output, element);
}
}
/** Used by {@link #read(Kryo, Input, Class)} to create the new object. This can be overridden to customize object creation, eg
* to call a constructor with arguments. The default implementation uses {@link Kryo#newInstance(Class)}. */
protected Collection create (Kryo kryo, Input input, Class type) {
return kryo.newInstance(type);
}
public Collection read (Kryo kryo, Input input, Class type) {
Collection collection = create(kryo, input, type);
kryo.reference(collection);
int length = input.readInt(true);
if (collection instanceof ArrayList) ((ArrayList)collection).ensureCapacity(length);
Class elementClass = this.elementClass;
Serializer serializer = this.serializer;
if (genericType != null) {
if (serializer == null) {
elementClass = genericType;
serializer = kryo.getSerializer(genericType);
}
genericType = null;
}
if (serializer != null) {
if (elementsCanBeNull) {
for (int i = 0; i < length; i++)
collection.add(kryo.readObjectOrNull(input, elementClass, serializer));
} else {
for (int i = 0; i < length; i++)
collection.add(kryo.readObject(input, elementClass, serializer));
}
} else {
for (int i = 0; i < length; i++)
collection.add(kryo.readClassAndObject(input));
}
return collection;
}
/** Used by {@link #copy(Kryo, Collection)} to create the new object. This can be overridden to customize object creation, eg to
* call a constructor with arguments. The default implementation uses {@link Kryo#newInstance(Class)}. */
protected Collection createCopy (Kryo kryo, Collection original) {
return kryo.newInstance(original.getClass());
}
public Collection copy (Kryo kryo, Collection original) {
Collection copy = createCopy(kryo, original);
kryo.reference(copy);
for (Object element : original)
copy.add(kryo.copy(element));
return copy;
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/serializers/CompatibleFieldSerializer.java 0000664 0000000 0000000 00000006540 12105756347 0033164 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.serializers;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.InputChunked;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.io.OutputChunked;
import com.esotericsoftware.kryo.util.ObjectMap;
import static com.esotericsoftware.minlog.Log.*;
/** Serializes objects using direct field assignment, with limited support for forward and backward compatibility. Fields can be
* added or removed without invalidating previously serialized bytes. Note that changing the type of a field is not supported.
*
* There is additional overhead compared to {@link FieldSerializer}. A header is output the first time an object of a given type
* is serialized. The header consists of an int for the number of fields, then a String for each field name. Also, to support
* skipping the bytes for a field that no longer exists, for each field value an int is written that is the length of the value in
* bytes.
*
* Note that the field data is identified by name. The situation where a super class has a field with the same name as a subclass
* must be avoided.
* @author Nathan Sweet */
public class CompatibleFieldSerializer extends FieldSerializer {
public CompatibleFieldSerializer (Kryo kryo, Class type) {
super(kryo, type);
}
public void write (Kryo kryo, Output output, T object) {
CachedField[] fields = getFields();
ObjectMap context = kryo.getGraphContext();
if (!context.containsKey(this)) {
context.put(this, null);
if (TRACE) trace("kryo", "Write " + fields.length + " field names.");
output.writeInt(fields.length, true);
for (int i = 0, n = fields.length; i < n; i++)
output.writeString(fields[i].field.getName());
}
OutputChunked outputChunked = new OutputChunked(output, 1024);
for (int i = 0, n = fields.length; i < n; i++) {
fields[i].write(outputChunked, object);
outputChunked.endChunks();
}
}
public T read (Kryo kryo, Input input, Class type) {
T object = kryo.newInstance(type);
kryo.reference(object);
ObjectMap context = kryo.getGraphContext();
CachedField[] fields = (CachedField[])context.get(this);
if (fields == null) {
int length = input.readInt(true);
if (TRACE) trace("kryo", "Read " + length + " field names.");
String[] names = new String[length];
for (int i = 0; i < length; i++)
names[i] = input.readString();
fields = new CachedField[length];
CachedField[] allFields = getFields();
outer:
for (int i = 0, n = names.length; i < n; i++) {
String schemaName = names[i];
for (int ii = 0, nn = allFields.length; ii < nn; ii++) {
if (allFields[ii].field.getName().equals(schemaName)) {
fields[i] = allFields[ii];
continue outer;
}
}
if (TRACE) trace("kryo", "Ignore obsolete field: " + schemaName);
}
context.put(this, fields);
}
InputChunked inputChunked = new InputChunked(input, 1024);
for (int i = 0, n = fields.length; i < n; i++) {
CachedField cachedField = fields[i];
if (cachedField == null) {
if (TRACE) trace("kryo", "Skip obsolete field.");
inputChunked.nextChunks();
continue;
}
cachedField.read(inputChunked, object);
inputChunked.nextChunks();
}
return object;
}
}
libkryo-java-2.20/java/src/com/esotericsoftware/kryo/serializers/DefaultArraySerializers.java 0000664 0000000 0000000 00000025473 12105756347 0032715 0 ustar 00root root 0000000 0000000
package com.esotericsoftware.kryo.serializers;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
import com.esotericsoftware.kryo.Kryo;
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 for specific array types that are provided by {@link Kryo#addDefaultSerializer(Class, Class)
* default}.
* @author Nathan Sweet */
public class DefaultArraySerializers {
static public class ByteArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, byte[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
output.writeBytes(object);
}
public byte[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
return input.readBytes(length - 1);
}
public byte[] copy (Kryo kryo, byte[] original) {
byte[] copy = new byte[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class IntArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, int[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeInt(object[i], false);
}
public int[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
int[] array = new int[--length];
for (int i = 0; i < length; i++)
array[i] = input.readInt(false);
return array;
}
public int[] copy (Kryo kryo, int[] original) {
int[] copy = new int[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class FloatArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, float[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeFloat(object[i]);
}
public float[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
float[] array = new float[--length];
for (int i = 0; i < length; i++)
array[i] = input.readFloat();
return array;
}
public float[] copy (Kryo kryo, float[] original) {
float[] copy = new float[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class LongArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, long[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeLong(object[i], false);
}
public long[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
long[] array = new long[--length];
for (int i = 0; i < length; i++)
array[i] = input.readLong(false);
return array;
}
public long[] copy (Kryo kryo, long[] original) {
long[] copy = new long[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class ShortArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, short[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeShort(object[i]);
}
public short[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
short[] array = new short[--length];
for (int i = 0; i < length; i++)
array[i] = input.readShort();
return array;
}
public short[] copy (Kryo kryo, short[] original) {
short[] copy = new short[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class CharArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, char[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeChar(object[i]);
}
public char[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
char[] array = new char[--length];
for (int i = 0; i < length; i++)
array[i] = input.readChar();
return array;
}
public char[] copy (Kryo kryo, char[] original) {
char[] copy = new char[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class DoubleArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, double[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeDouble(object[i]);
}
public double[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
double[] array = new double[--length];
for (int i = 0; i < length; i++)
array[i] = input.readDouble();
return array;
}
public double[] copy (Kryo kryo, double[] original) {
double[] copy = new double[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class BooleanArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, boolean[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeBoolean(object[i]);
}
public boolean[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
boolean[] array = new boolean[--length];
for (int i = 0; i < length; i++)
array[i] = input.readBoolean();
return array;
}
public boolean[] copy (Kryo kryo, boolean[] original) {
boolean[] copy = new boolean[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class StringArraySerializer extends Serializer {
{
setAcceptsNull(true);
}
public void write (Kryo kryo, Output output, String[] object) {
if (object == null) {
output.writeByte(NULL);
return;
}
output.writeInt(object.length + 1, true);
for (int i = 0, n = object.length; i < n; i++)
output.writeString(object[i]);
}
public String[] read (Kryo kryo, Input input, Class type) {
int length = input.readInt(true);
if (length == NULL) return null;
String[] array = new String[--length];
for (int i = 0; i < length; i++)
array[i] = input.readString();
return array;
}
public String[] copy (Kryo kryo, String[] original) {
String[] copy = new String[original.length];
System.arraycopy(original, 0, copy, 0, copy.length);
return copy;
}
}
static public class ObjectArraySerializer extends Serializer