├── .classpath
├── .project
├── .settings
├── org.eclipse.jdt.core.prefs
└── org.eclipse.jdt.ui.prefs
├── build
├── junit-4.6.jar
├── minlog-1.2.jar
└── minlog-none-1.2.jar
├── lib
├── asm-4.0.jar
├── minlog-1.2.jar
├── objenesis-1.2.jar
└── reflectasm-1.07.jar
├── license.txt
├── pom.xml
├── project.yaml
├── src
└── com
│ └── esotericsoftware
│ └── kryo
│ ├── ClassResolver.java
│ ├── DefaultSerializer.java
│ ├── Generics.java
│ ├── Kryo.java
│ ├── KryoCopyable.java
│ ├── KryoException.java
│ ├── KryoSerializable.java
│ ├── NotNull.java
│ ├── ReferenceResolver.java
│ ├── Registration.java
│ ├── Serializer.java
│ ├── StreamFactory.java
│ ├── factories
│ ├── PseudoSerializerFactory.java
│ ├── ReflectionSerializerFactory.java
│ └── SerializerFactory.java
│ ├── io
│ ├── ByteBufferInput.java
│ ├── ByteBufferInputStream.java
│ ├── ByteBufferOutput.java
│ ├── ByteBufferOutputStream.java
│ ├── FastInput.java
│ ├── FastOutput.java
│ ├── Input.java
│ ├── InputChunked.java
│ ├── Output.java
│ ├── OutputChunked.java
│ ├── UnsafeInput.java
│ ├── UnsafeMemoryInput.java
│ ├── UnsafeMemoryOutput.java
│ └── UnsafeOutput.java
│ ├── serializers
│ ├── AsmCacheFields.java
│ ├── AsmCachedFieldFactory.java
│ ├── BeanSerializer.java
│ ├── BlowfishSerializer.java
│ ├── CollectionSerializer.java
│ ├── CompatibleFieldSerializer.java
│ ├── DefaultArraySerializers.java
│ ├── DefaultSerializers.java
│ ├── DeflateSerializer.java
│ ├── FieldSerializer.java
│ ├── FieldSerializerGenericsUtil.java
│ ├── FieldSerializerUnsafeUtil.java
│ ├── JavaSerializer.java
│ ├── MapSerializer.java
│ ├── ObjectCachedFieldFactory.java
│ ├── ObjectField.java
│ ├── TaggedFieldSerializer.java
│ ├── UnsafeCacheFields.java
│ └── UnsafeCachedFieldFactory.java
│ └── util
│ ├── DefaultClassResolver.java
│ ├── DefaultStreamFactory.java
│ ├── FastestStreamFactory.java
│ ├── IdentityMap.java
│ ├── IdentityObjectIntMap.java
│ ├── IntArray.java
│ ├── IntMap.java
│ ├── ListReferenceResolver.java
│ ├── MapReferenceResolver.java
│ ├── ObjectMap.java
│ ├── UnsafeUtil.java
│ └── Util.java
└── test
└── com
└── esotericsoftware
└── kryo
├── ArraySerializerTest.java
├── BeanSerializerTest.java
├── BlowfishSerializerTest.java
├── ChunkedTest.java
├── CollectionSerializerTest.java
├── CompatibleFieldSerializerTest.java
├── CopyTest.java
├── DefaultSerializersTest.java
├── DeflateSerializerTest.java
├── FieldSerializerTest.java
├── InputOutputTest.java
├── JavaSerializerTest.java
├── KryoTestCase.java
├── MapSerializerTest.java
├── ReferenceTest.java
├── SerializationBenchmarkTest.java
├── TaggedFieldSerializerTest.java
├── UnsafeInputOutputTest.java
└── UnsafeMemoryInputOutputTest.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | kryo2
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.ui.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | formatter_profile=_libgdx
3 | formatter_settings_version=12
4 |
--------------------------------------------------------------------------------
/build/junit-4.6.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/build/junit-4.6.jar
--------------------------------------------------------------------------------
/build/minlog-1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/build/minlog-1.2.jar
--------------------------------------------------------------------------------
/build/minlog-none-1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/build/minlog-none-1.2.jar
--------------------------------------------------------------------------------
/lib/asm-4.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/lib/asm-4.0.jar
--------------------------------------------------------------------------------
/lib/minlog-1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/lib/minlog-1.2.jar
--------------------------------------------------------------------------------
/lib/objenesis-1.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/lib/objenesis-1.2.jar
--------------------------------------------------------------------------------
/lib/reflectasm-1.07.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svn2github/kryo/5735e1b339ae6947050872a60c67b575238d221d/lib/reflectasm-1.07.jar
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008, Nathan Sweet
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5 |
6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7 | * 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.
8 | * 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.
9 |
10 | 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.
11 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
5 | 4.0.0
6 |
7 | org.sonatype.oss
8 | oss-parent
9 | 7
10 |
11 | com.esotericsoftware.kryo
12 | kryo
13 | 2.23-SNAPSHOT
14 | bundle
15 | Kryo
16 | Fast, efficient Java serialization
17 | http://code.google.com/p/kryo/
18 |
19 |
20 |
21 | New BSD License
22 | http://www.opensource.org/licenses/bsd-license.php
23 | repo
24 |
25 |
26 |
27 |
28 | http://kryo.googlecode.com/svn/
29 | scm:svn:http://kryo.googlecode.com/svn/
30 |
31 |
32 |
33 |
34 | nathan.sweet
35 | Nathan Sweet
36 | nathan.sweet@gmail.com
37 |
38 |
39 |
40 |
41 | UTF-8
42 |
43 |
44 |
45 |
46 | com.esotericsoftware.reflectasm
47 | reflectasm
48 | 1.07
49 | shaded
50 |
51 |
52 | org.ow2.asm
53 | asm
54 |
55 |
56 |
57 |
58 | com.esotericsoftware.minlog
59 | minlog
60 | 1.2
61 |
62 |
63 | org.objenesis
64 | objenesis
65 | 1.2
66 |
67 |
68 | junit
69 | junit
70 | 4.8.2
71 | test
72 |
73 |
74 |
75 |
76 |
77 | src
78 | test
79 |
80 |
81 |
82 |
83 | org.apache.maven.plugins
84 | maven-compiler-plugin
85 | true
86 |
87 | 1.5
88 | 1.5
89 | utf-8
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | maven-resources-plugin
98 | 2.5
99 |
100 |
101 | default-resources
102 | none
103 |
104 |
105 | default-testResources
106 | none
107 |
108 |
109 |
110 |
111 | org.apache.maven.plugins
112 | maven-jar-plugin
113 | 2.4
114 |
115 |
116 | **/.svn/*
117 |
118 |
119 |
120 |
121 | org.apache.maven.plugins
122 | maven-shade-plugin
123 | 2.1
124 |
125 |
126 | true
127 | false
128 |
129 |
130 | com.esotericsoftware.reflectasm:reflectasm:shaded
131 | com.esotericsoftware.minlog:minlog
132 | org.objenesis:objenesis
133 |
134 |
135 |
136 |
137 | org.objenesis
138 | com.esotericsoftware.shaded.org.objenesis
139 |
140 |
141 |
142 |
143 |
144 | package
145 |
146 | shade
147 |
148 |
149 |
150 |
151 |
152 | org.apache.felix
153 | maven-bundle-plugin
154 | true
155 |
156 |
157 |
164 |
165 | com.esotericsoftware*, org.objenesis*
166 | *;scope=compile|runtime
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | requireSnapshot
176 |
178 |
179 |
180 |
181 |
182 | maven-enforcer-plugin
183 |
184 |
185 |
186 | enforce
187 |
188 |
189 |
190 |
191 | "${project.version}".endsWith("-SNAPSHOT")
192 | Jenkins should only build -SNAPSHOT versions
193 |
194 |
195 | true
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 | sonatype-releases
208 | sonatype releases repo
209 | https://oss.sonatype.org/content/repositories/releases
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/project.yaml:
--------------------------------------------------------------------------------
1 | name: kryo
2 | version: 2.22
3 | ---
4 | Build.build(project);
5 | Build.oneJAR(project);
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/ClassResolver.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | import com.esotericsoftware.kryo.io.Input;
5 | import com.esotericsoftware.kryo.io.Output;
6 |
7 | /** Handles class registration, writing class identifiers to bytes, and reading class identifiers from bytes.
8 | * @author Nathan Sweet */
9 | public interface ClassResolver {
10 | /** Sets the Kryo instance that this ClassResolver will be used for. This is called automatically by Kryo. */
11 | public void setKryo (Kryo kryo);
12 |
13 | /** Stores the specified registration.
14 | * @see Kryo#register(Registration) */
15 | public Registration register (Registration registration);
16 |
17 | /** Called when an unregistered type is encountered and {@link Kryo#setRegistrationRequired(boolean)} is false. */
18 | public Registration registerImplicit (Class type);
19 |
20 | /** Returns the registration for the specified class, or null if the class is not registered. */
21 | public Registration getRegistration (Class type);
22 |
23 | /** Returns the registration for the specified ID, or null if no class is registered with that ID. */
24 | public Registration getRegistration (int classID);
25 |
26 | /** Writes a class and returns its registration.
27 | * @param type May be null.
28 | * @return Will be null if type is null. */
29 | public Registration writeClass (Output output, Class type);
30 |
31 | /** Reads a class and returns its registration.
32 | * @return May be null. */
33 | public Registration readClass (Input input);
34 |
35 | /** Called by {@link Kryo#reset()}. */
36 | public void reset ();
37 | }
38 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/DefaultSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | /** Sets the default serializer to use for the annotated class. The specified Serializer class must have a constructor taking a
10 | * Kryo instance and a class, a Kryo instance, a class, or no arguments.
11 | * @see Kryo#register(Class)
12 | * @author Nathan Sweet */
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Target(ElementType.TYPE)
15 | public @interface DefaultSerializer {
16 | Class extends Serializer> value();
17 | }
18 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/Generics.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo;
2 |
3 | import static com.esotericsoftware.minlog.Log.TRACE;
4 | import static com.esotericsoftware.minlog.Log.trace;
5 |
6 | import java.lang.reflect.Array;
7 | import java.lang.reflect.GenericArrayType;
8 | import java.lang.reflect.ParameterizedType;
9 | import java.lang.reflect.Type;
10 | import java.lang.reflect.TypeVariable;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | /***
15 | * Helper class to map type name variables to concrete classes that are used during instantiation
16 |
17 | * @author Roman Levenstein
18 | *
19 | */
20 | public class Generics {
21 | private Map typeVar2class;
22 |
23 | private Generics parentScope;
24 |
25 | public Generics() {
26 | typeVar2class = new HashMap();
27 | parentScope = null;
28 | }
29 |
30 | public Generics(Map mappings) {
31 | typeVar2class = new HashMap(mappings);
32 | parentScope = null;
33 | }
34 |
35 | public Generics(Generics parentScope) {
36 | typeVar2class = new HashMap();
37 | this.parentScope = parentScope;
38 | }
39 |
40 | public void add(String typeVar, Class clazz) {
41 | typeVar2class.put(typeVar, clazz);
42 | }
43 |
44 | public Class getConcreteClass(String typeVar) {
45 | Class clazz = typeVar2class.get(typeVar);
46 | if(clazz == null && parentScope != null)
47 | return parentScope.getConcreteClass(typeVar);
48 | return clazz;
49 | }
50 |
51 | public void setParentScope(Generics scope) {
52 | if(parentScope != null)
53 | throw new RuntimeException("Parent scope can be set just once");
54 | parentScope = scope;
55 | }
56 |
57 | public Generics getParentScope() {
58 | return parentScope;
59 | }
60 |
61 | public String toString() {
62 | return typeVar2class.toString();
63 | }
64 |
65 | public void resetParentScope() {
66 | parentScope = null;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/KryoCopyable.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | /** Allows implementing classes to perform their own copying. Hand written copying can be more efficient in some cases.
5 | *
6 | * This method is used instead of the registered serializer {@link Serializer#copy(Kryo, Object)} method.
7 | * @author Nathan Sweet */
8 | public interface KryoCopyable {
9 | /** Returns a copy that has the same values as this object. Before Kryo can be used to copy child objects,
10 | * {@link Kryo#reference(Object)} must be called with the copy to ensure it can be referenced by the child objects.
11 | * @see Serializer#copy(Kryo, Object) */
12 | public T copy (Kryo kryo);
13 | }
14 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/KryoException.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | /** General Kryo RuntimeException.
5 | * @author Nathan Sweet */
6 | public class KryoException extends RuntimeException {
7 | private StringBuffer trace;
8 |
9 | public KryoException () {
10 | super();
11 | }
12 |
13 | public KryoException (String message, Throwable cause) {
14 | super(message, cause);
15 | }
16 |
17 | public KryoException (String message) {
18 | super(message);
19 | }
20 |
21 | public KryoException (Throwable cause) {
22 | super(cause);
23 | }
24 |
25 | public String getMessage () {
26 | if (trace == null) return super.getMessage();
27 | StringBuffer buffer = new StringBuffer(512);
28 | buffer.append(super.getMessage());
29 | if (buffer.length() > 0) buffer.append('\n');
30 | buffer.append("Serialization trace:");
31 | buffer.append(trace);
32 | return buffer.toString();
33 | }
34 |
35 | /** Adds information to the exception message about where in the the object graph serialization failure occurred.
36 | * {@link Serializer Serializers} can catch {@link KryoException}, add trace information, and rethrow the exception. */
37 | public void addTrace (String info) {
38 | if (info == null) throw new IllegalArgumentException("info cannot be null.");
39 | if (trace == null) trace = new StringBuffer(512);
40 | trace.append('\n');
41 | trace.append(info);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/KryoSerializable.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | import com.esotericsoftware.kryo.io.Input;
5 | import com.esotericsoftware.kryo.io.Output;
6 | import com.esotericsoftware.kryo.serializers.DefaultSerializers.KryoSerializableSerializer;
7 |
8 | /** Allows implementing classes to perform their own serialization. Hand written serialization can be more efficient in some cases.
9 | *
10 | * The default serializer for KryoSerializable is {@link KryoSerializableSerializer}, which uses {@link Kryo#newInstance(Class)}
11 | * to construct the class.
12 | * @author Nathan Sweet */
13 | public interface KryoSerializable {
14 | public void write (Kryo kryo, Output output);
15 |
16 | public void read (Kryo kryo, Input input);
17 | }
18 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/NotNull.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | import java.lang.annotation.ElementType;
5 | import java.lang.annotation.Retention;
6 | import java.lang.annotation.RetentionPolicy;
7 | import java.lang.annotation.Target;
8 |
9 | import com.esotericsoftware.kryo.serializers.FieldSerializer;
10 |
11 | /** Indicates a field can never be null when it is being serialized and deserialized. Some serializers use this to save space. Eg,
12 | * {@link FieldSerializer} may save 1 byte per field.
13 | * @author Nathan Sweet */
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Target(ElementType.FIELD)
16 | public @interface NotNull {
17 | }
18 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/ReferenceResolver.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | /** When references are enabled, this tracks objects that have already been read or written, provides an ID for objects that are
5 | * written, and looks up by ID objects that have been read.
6 | * @author Nathan Sweet */
7 | public interface ReferenceResolver {
8 | /** Sets the Kryo instance that this ClassResolver will be used for. This is called automatically by Kryo. */
9 | public void setKryo (Kryo kryo);
10 |
11 | /** Returns an ID for the object if it has been written previously, otherwise returns -1. */
12 | public int getWrittenId (Object object);
13 |
14 | /** Returns a new ID for an object that is being written for the first time.
15 | * @return The ID, which is stored more efficiently if it is positive and must not be -1 or -2. */
16 | public int addWrittenObject (Object object);
17 |
18 | /** Reserves the ID for the next object that will be read. This is called only the first time an object is encountered.
19 | * @param type The type of object that will be read.
20 | * @return The ID, which is stored more efficiently if it is positive and must not be -1 or -2. */
21 | public int nextReadId (Class type);
22 |
23 | /** Sets the ID for an object that has been read.
24 | * @param id The ID from {@link #nextReadId(Class)}. */
25 | public void setReadObject (int id, Object object);
26 |
27 | /** Returns the object for the specified ID. The ID and object are guaranteed to have been previously passed in a call to
28 | * {@link #setReadObject(int, Object)}. */
29 | public Object getReadObject (Class type, int id);
30 |
31 | /** Called by {@link Kryo#reset()}. */
32 | public void reset ();
33 |
34 | /** Returns true if references will be written for the specified type.
35 | * @param type Will never be a primitive type, but may be a primitive type wrapper. */
36 | public boolean useReferences (Class type);
37 | }
38 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/Registration.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | import org.objenesis.instantiator.ObjectInstantiator;
5 |
6 | import static com.esotericsoftware.kryo.util.Util.*;
7 | import static com.esotericsoftware.minlog.Log.*;
8 |
9 | /** Describes the {@link Serializer} and class ID to use for a class.
10 | * @author Nathan Sweet */
11 | public class Registration {
12 | private final Class type;
13 | private final int id;
14 | private Serializer serializer;
15 | private ObjectInstantiator instantiator;
16 |
17 | public Registration (Class type, Serializer serializer, int id) {
18 | if (type == null) throw new IllegalArgumentException("type cannot be null.");
19 | if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
20 | this.type = type;
21 | this.serializer = serializer;
22 | this.id = id;
23 | }
24 |
25 | public Class getType () {
26 | return type;
27 | }
28 |
29 | /** Returns the registered class ID.
30 | * @see Kryo#register(Class) */
31 | public int getId () {
32 | return id;
33 | }
34 |
35 | public Serializer getSerializer () {
36 | return serializer;
37 | }
38 |
39 | public void setSerializer (Serializer serializer) {
40 | if (serializer == null) throw new IllegalArgumentException("serializer cannot be null.");
41 | this.serializer = serializer;
42 | if (TRACE) trace("kryo", "Update registered serializer: " + type.getName() + " (" + serializer.getClass().getName() + ")");
43 | }
44 |
45 | /** @return May be null if not yet set. */
46 | public ObjectInstantiator getInstantiator () {
47 | return instantiator;
48 | }
49 |
50 | /** Sets the instantiator that will create a new instance of the type in {@link Kryo#newInstance(Class)}. */
51 | public void setInstantiator (ObjectInstantiator instantiator) {
52 | if (instantiator == null) throw new IllegalArgumentException("instantiator cannot be null.");
53 | this.instantiator = instantiator;
54 | }
55 |
56 | public String toString () {
57 | return "[" + id + ", " + className(type) + "]";
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/Serializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo;
3 |
4 | import com.esotericsoftware.kryo.io.Input;
5 | import com.esotericsoftware.kryo.io.Output;
6 |
7 | /** Reads and writes objects to and from bytes.
8 | * @author Nathan Sweet */
9 | public abstract class Serializer {
10 | private boolean acceptsNull, immutable;
11 |
12 | public Serializer () {
13 | }
14 |
15 | /** @see #setAcceptsNull(boolean) */
16 | public Serializer (boolean acceptsNull) {
17 | this.acceptsNull = acceptsNull;
18 | }
19 |
20 | /** @see #setAcceptsNull(boolean)
21 | * @see #setImmutable(boolean) */
22 | public Serializer (boolean acceptsNull, boolean immutable) {
23 | this.acceptsNull = acceptsNull;
24 | this.immutable = immutable;
25 | }
26 |
27 | /** Writes the bytes for the object to the output.
28 | *
29 | * This method should not be called directly, instead this serializer can be passed to {@link Kryo} write methods that accept a
30 | * serialier.
31 | * @param object May be null if {@link #getAcceptsNull()} is true. */
32 | abstract public void write (Kryo kryo, Output output, T object);
33 |
34 | /** Reads bytes and returns a new object of the specified concrete type.
35 | *
36 | * Before Kryo can be used to read child objects, {@link Kryo#reference(Object)} must be called with the parent object to
37 | * ensure it can be referenced by the child objects. Any serializer that uses {@link Kryo} to read a child object may need to
38 | * be reentrant.
39 | *
40 | * This method should not be called directly, instead this serializer can be passed to {@link Kryo} read methods that accept a
41 | * serialier.
42 | * @return May be null if {@link #getAcceptsNull()} is true. */
43 | abstract public T read (Kryo kryo, Input input, Class type);
44 |
45 | public boolean getAcceptsNull () {
46 | return acceptsNull;
47 | }
48 |
49 | /** If true, this serializer will handle writing and reading null values. If false, the Kryo framework handles null values and
50 | * the serializer will never receive null.
51 | *
52 | * This can be set to true on a serializer that does not accept nulls if it is known that the serializer will never encounter
53 | * null. Doing this will prevent the framework from writing a byte to denote null. */
54 | public void setAcceptsNull (boolean acceptsNull) {
55 | this.acceptsNull = acceptsNull;
56 | }
57 |
58 | public boolean isImmutable () {
59 | return immutable;
60 | }
61 |
62 | /** If true, the type this serializer will be used for is considered immutable. This causes {@link #copy(Kryo, Object)} to
63 | * return the original object. */
64 | public void setImmutable (boolean immutable) {
65 | this.immutable = immutable;
66 | }
67 |
68 | /** Sets the generic types of the field or method this serializer will be used for on the next call to read or write. Subsequent
69 | * calls to read and write must not use this generic type information. The default implementation does nothing. Subclasses may
70 | * use the information provided to this method for more efficient serialization, eg to use the same type for all items in a
71 | * list.
72 | * @param generics Some (but never all) elements may be null if there is no generic type information at that index. */
73 | public void setGenerics (Kryo kryo, Class[] generics) {
74 | }
75 |
76 | /** Returns a copy of the specified object. The default implementation returns the original if {@link #isImmutable()} is true,
77 | * else throws {@link KryoException}. Subclasses should override this method if needed to support {@link Kryo#copy(Object)}.
78 | *
79 | * Before Kryo can be used to copy child objects, {@link Kryo#reference(Object)} must be called with the copy to ensure it can
80 | * be referenced by the child objects. Any serializer that uses {@link Kryo} to copy a child object may need to be reentrant.
81 | *
82 | * This method should not be called directly, instead this serializer can be passed to {@link Kryo} copy methods that accept a
83 | * serialier. */
84 | public T copy (Kryo kryo, T original) {
85 | if (immutable) return original;
86 | throw new KryoException("Serializer does not support copy: " + getClass().getName());
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/StreamFactory.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo;
2 |
3 | import java.io.InputStream;
4 | import java.io.OutputStream;
5 |
6 | import com.esotericsoftware.kryo.io.Input;
7 | import com.esotericsoftware.kryo.io.Output;
8 |
9 | /** Provides input and output streams based on system settings.
10 | * @author Roman Levenstein */
11 | public interface StreamFactory {
12 |
13 | /** Creates an uninitialized Input. */
14 | public Input getInput ();
15 |
16 | /** Creates a new Input for reading from a byte array.
17 | * @param bufferSize The size of the buffer. An exception is thrown if more bytes than this are read. */
18 | public Input getInput(int bufferSize);
19 |
20 | /** Creates a new Input for reading from a byte array.
21 | * @param buffer An exception is thrown if more bytes than this are read. */
22 | public Input getInput(byte[] buffer) ;
23 |
24 | /** Creates a new Input for reading from a byte array.
25 | * @param buffer An exception is thrown if more bytes than this are read. */
26 | public Input getInput(byte[] buffer, int offset, int count) ;
27 |
28 | /** Creates a new Input for reading from an InputStream with a buffer size of 4096. */
29 | public Input getInput(InputStream inputStream);
30 |
31 | /** Creates a new Input for reading from an InputStream. */
32 | public Input getInput(InputStream inputStream, int bufferSize);
33 |
34 | /** Creates an uninitialized Output. {@link Output#setBuffer(byte[], int)} must be called before the Output is used. */
35 | public Output getOutput();
36 |
37 | /** Creates a new Output for writing to a byte array.
38 | * @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
39 | public Output getOutput(int bufferSize);
40 |
41 | /** Creates a new Output for writing to a byte array.
42 | * @param bufferSize The initial size of the buffer.
43 | * @param maxBufferSize The buffer is doubled as needed until it exceeds maxBufferSize and an exception is thrown. Can be -1
44 | * for no maximum. */
45 | public Output getOutput(int bufferSize, int maxBufferSize);
46 |
47 | /** Creates a new Output for writing to a byte array.
48 | * @see Output#setBuffer(byte[]) */
49 | public Output getOutput(byte[] buffer);
50 |
51 | /** Creates a new Output for writing to a byte array.
52 | * @see Output#setBuffer(byte[], int) */
53 | public Output getOutput(byte[] buffer, int maxBufferSize);
54 |
55 | /** Creates a new Output for writing to an OutputStream. A buffer size of 4096 is used. */
56 | public Output getOutput(OutputStream outputStream);
57 |
58 | /** Creates a new Output for writing to an OutputStream. */
59 | public Output getOutput(OutputStream outputStream, int bufferSize);
60 |
61 | public void setKryo(Kryo kryo);
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/factories/PseudoSerializerFactory.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo.factories;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.Serializer;
5 |
6 | /**
7 | * A serializer factory that always returns a given serializer instance. This implementation of {@link SerializerFactory}
8 | * is not a real factory since it only provides a given instance instead of dynamically creating new serializers. It can
9 | * be used when all types should be serialized by the same serializer. This also allows serializers to be shared among different
10 | * {@link Kryo} instances.
11 | *
12 | * @author Rafael Winterhalter
13 | */
14 | public class PseudoSerializerFactory implements SerializerFactory {
15 |
16 | private final Serializer> serializer;
17 |
18 | public PseudoSerializerFactory (Serializer> serializer) {
19 | this.serializer = serializer;
20 | }
21 |
22 | @Override
23 | public Serializer makeSerializer (Kryo kryo, Class> type) {
24 | return serializer;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/factories/ReflectionSerializerFactory.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo.factories;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.Serializer;
5 |
6 | import static com.esotericsoftware.kryo.util.Util.className;
7 |
8 | /**
9 | * This factory instantiates new serializers of a given class via reflection. The constructors of the given {@code serializerClass}
10 | * must either take an instance of {@link Kryo} and an instance of {@link Class} as its parameter, take only a {@link Kryo} or {@link Class}
11 | * as its only argument or take no arguments. If several of the described constructors are found, the first found constructor is used,
12 | * in the order as they were just described.
13 | *
14 | * @author Rafael Winterhalter
15 | */
16 | public class ReflectionSerializerFactory implements SerializerFactory {
17 |
18 | private final Class extends Serializer> serializerClass;
19 |
20 | public ReflectionSerializerFactory (Class extends Serializer> serializerClass) {
21 | this.serializerClass = serializerClass;
22 | }
23 |
24 | @Override
25 | public Serializer makeSerializer (Kryo kryo, Class> type) {
26 | return makeSerializer(kryo, serializerClass, type);
27 | }
28 |
29 | /** Creates a new instance of the specified serializer for serializing the specified class. Serializers must have a zero
30 | * argument constructor or one that takes (Kryo), (Class), or (Kryo, Class).
31 | */
32 | public static Serializer makeSerializer (Kryo kryo, Class extends Serializer> serializerClass, Class> type) {
33 | try {
34 | try {
35 | return serializerClass.getConstructor(Kryo.class, Class.class).newInstance(kryo, type);
36 | } catch (NoSuchMethodException ex1) {
37 | try {
38 | return serializerClass.getConstructor(Kryo.class).newInstance(kryo);
39 | } catch (NoSuchMethodException ex2) {
40 | try {
41 | return serializerClass.getConstructor(Class.class).newInstance(type);
42 | } catch (NoSuchMethodException ex3) {
43 | return serializerClass.newInstance();
44 | }
45 | }
46 | }
47 | } catch (Exception ex) {
48 | throw new IllegalArgumentException("Unable to create serializer \"" + serializerClass.getName() + "\" for class: " + className(type), ex);
49 | }
50 |
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/factories/SerializerFactory.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo.factories;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.Serializer;
5 |
6 | /**
7 | * A serializer factory that allows the creation of serializers. This factory will be called when a {@link Kryo}
8 | * serializer discovers a new type for which no serializer is yet known. For example, when a factory is registered
9 | * via {@link Kryo#setDefaultSerializer(SerializerFactory)} a different serializer can be created dependent on the
10 | * type of a class.
11 | *
12 | * @author Rafael Winterhalter
13 | */
14 | public interface SerializerFactory {
15 |
16 | /**
17 | * Creates a new serializer
18 | * @param kryo The serializer instance requesting the new serializer.
19 | * @param type The type of the object that is to be serialized.
20 | * @return An implementation of a serializer that is able to serialize an object of type {@code type}.
21 | */
22 | Serializer makeSerializer (Kryo kryo, Class> type);
23 | }
24 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/ByteBufferInputStream.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.nio.ByteBuffer;
7 |
8 | /** An InputStream whose source is a {@link ByteBuffer}.
9 | * @author Nathan Sweet */
10 | public class ByteBufferInputStream extends InputStream {
11 | private ByteBuffer byteBuffer;
12 |
13 | public ByteBufferInputStream () {
14 | }
15 |
16 | /** Creates a stream with a new non-direct buffer of the specified size. The position and limit of the buffer is zero. */
17 | public ByteBufferInputStream (int bufferSize) {
18 | this(ByteBuffer.allocate(bufferSize));
19 | byteBuffer.flip();
20 | }
21 |
22 | /** Creates an uninitialized stream that cannot be used until {@link #setByteBuffer(ByteBuffer)} is called. */
23 | public ByteBufferInputStream (ByteBuffer byteBuffer) {
24 | this.byteBuffer = byteBuffer;
25 | }
26 |
27 | public ByteBuffer getByteBuffer () {
28 | return byteBuffer;
29 | }
30 |
31 | public void setByteBuffer (ByteBuffer byteBuffer) {
32 | this.byteBuffer = byteBuffer;
33 | }
34 |
35 | public int read () throws IOException {
36 | if (!byteBuffer.hasRemaining()) return -1;
37 | return byteBuffer.get();
38 | }
39 |
40 | public int read (byte[] bytes, int offset, int length) throws IOException {
41 | int count = Math.min(byteBuffer.remaining(), length);
42 | if (count == 0) return -1;
43 | byteBuffer.get(bytes, offset, count);
44 | return count;
45 | }
46 |
47 | public int available () throws IOException {
48 | return byteBuffer.remaining();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/ByteBufferOutputStream.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 | import java.nio.ByteBuffer;
7 |
8 | /** An OutputStream whose target is a {@link ByteBuffer}. If bytes would be written that would overflow the buffer,
9 | * {@link #flush()} is called. Subclasses can override flush to empty the buffer.
10 | * @author Nathan Sweet */
11 | public class ByteBufferOutputStream extends OutputStream {
12 | private ByteBuffer byteBuffer;
13 |
14 | /** Creates an uninitialized stream that cannot be used until {@link #setByteBuffer(ByteBuffer)} is called. */
15 | public ByteBufferOutputStream () {
16 | }
17 |
18 | /** Creates a stream with a new non-direct buffer of the specified size. */
19 | public ByteBufferOutputStream (int bufferSize) {
20 | this(ByteBuffer.allocate(bufferSize));
21 | }
22 |
23 | public ByteBufferOutputStream (ByteBuffer byteBuffer) {
24 | this.byteBuffer = byteBuffer;
25 | }
26 |
27 | public ByteBuffer getByteBuffer () {
28 | return byteBuffer;
29 | }
30 |
31 | public void setByteBuffer (ByteBuffer byteBuffer) {
32 | this.byteBuffer = byteBuffer;
33 | }
34 |
35 | public void write (int b) throws IOException {
36 | if (!byteBuffer.hasRemaining()) flush();
37 | byteBuffer.put((byte)b);
38 | }
39 |
40 | public void write (byte[] bytes, int offset, int length) throws IOException {
41 | if (byteBuffer.remaining() < length) flush();
42 | byteBuffer.put(bytes, offset, length);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/FastInput.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.io.OutputStream;
7 |
8 | import sun.misc.Unsafe;
9 |
10 | import com.esotericsoftware.kryo.KryoException;
11 |
12 | /** Same as Input, but does not use variable length encoding for integer types.
13 | * @author Roman Levenstein */
14 | public final class FastInput extends Input {
15 |
16 | /** Creates an uninitialized Output. {@link #setBuffer(byte[], int, int)} must be called before the Output is used. */
17 | public FastInput () {
18 | }
19 |
20 | /** Creates a new Output for writing to a byte array.
21 | * @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
22 | public FastInput (int bufferSize) {
23 | super(bufferSize);
24 | }
25 |
26 | /** Creates a new Output for writing to a byte array.
27 | * @see #setBuffer(byte[]) */
28 | public FastInput (byte[] buffer) {
29 | super(buffer);
30 | }
31 |
32 | /** Creates a new Output for writing to a byte array.
33 | * @see #setBuffer(byte[], int, int) */
34 | public FastInput (byte[] buffer, int offset, int count) {
35 | super(buffer, offset, count);
36 | }
37 |
38 | /** Creates a new Output for writing to an OutputStream. A buffer size of 4096 is used. */
39 | public FastInput (InputStream outputStream) {
40 | super(outputStream);
41 | }
42 |
43 | /** Creates a new Output for writing to an OutputStream. */
44 | public FastInput (InputStream outputStream, int bufferSize) {
45 | super(outputStream, bufferSize);
46 | }
47 |
48 | public int readInt (boolean optimizePositive) throws KryoException {
49 | return readInt();
50 | }
51 |
52 | public long readLong (boolean optimizePositive) throws KryoException {
53 | return readLong();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/FastOutput.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.DataOutput;
5 | import java.io.IOException;
6 | import java.io.OutputStream;
7 |
8 | import sun.misc.Unsafe;
9 |
10 | import com.esotericsoftware.kryo.KryoException;
11 |
12 | /** Same as Output, but does not use variable length encoding for integer types.
13 | * @author Roman Levenstein */
14 | public final class FastOutput extends Output {
15 |
16 | /** Creates an uninitialized Output. {@link #setBuffer(byte[], int)} must be called before the Output is used. */
17 | public FastOutput () {
18 | }
19 |
20 | /** Creates a new Output for writing to a byte array.
21 | *
22 | * @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
23 | public FastOutput (int bufferSize) {
24 | this(bufferSize, bufferSize);
25 | }
26 |
27 | /** Creates a new Output for writing to a byte array.
28 | *
29 | * @param bufferSize The initial size of the buffer.
30 | * @param maxBufferSize The buffer is doubled as needed until it exceeds maxBufferSize and an exception is thrown. */
31 | public FastOutput (int bufferSize, int maxBufferSize) {
32 | super(bufferSize, maxBufferSize);
33 | }
34 |
35 | /** Creates a new Output for writing to a byte array.
36 | *
37 | * @see #setBuffer(byte[]) */
38 | public FastOutput (byte[] buffer) {
39 | this(buffer, buffer.length);
40 | }
41 |
42 | /** Creates a new Output for writing to a byte array.
43 | *
44 | * @see #setBuffer(byte[], int) */
45 | public FastOutput (byte[] buffer, int maxBufferSize) {
46 | super(buffer, maxBufferSize);
47 | }
48 |
49 | /** Creates a new Output for writing to an OutputStream. A buffer size of 4096 is used. */
50 | public FastOutput (OutputStream outputStream) {
51 | super(outputStream);
52 | }
53 |
54 | /** Creates a new Output for writing to an OutputStream. */
55 | public FastOutput (OutputStream outputStream, int bufferSize) {
56 | super(outputStream, bufferSize);
57 | }
58 |
59 | public int writeInt (int value, boolean optimizePositive) throws KryoException {
60 | writeInt(value);
61 | return 4;
62 | }
63 |
64 | public int writeLong (long value, boolean optimizePositive) throws KryoException {
65 | writeLong(value);
66 | return 8;
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/InputChunked.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import com.esotericsoftware.kryo.KryoException;
8 |
9 | import static com.esotericsoftware.minlog.Log.*;
10 |
11 | /** An InputStream that reads lengths and chunks of data from another OutputStream, allowing chunks to be skipped.
12 | * @author Nathan Sweet */
13 | public class InputChunked extends Input {
14 | private int chunkSize = -1;
15 |
16 | /** Creates an uninitialized InputChunked with a buffer size of 2048. The InputStream must be set before it can be used. */
17 | public InputChunked () {
18 | super(2048);
19 | }
20 |
21 | /** Creates an uninitialized InputChunked. The InputStream must be set before it can be used. */
22 | public InputChunked (int bufferSize) {
23 | super(bufferSize);
24 | }
25 |
26 | /** Creates an InputChunked with a buffer size of 2048. */
27 | public InputChunked (InputStream inputStream) {
28 | super(inputStream, 2048);
29 | }
30 |
31 | public InputChunked (InputStream inputStream, int bufferSize) {
32 | super(inputStream, bufferSize);
33 | }
34 |
35 | public void setInputStream (InputStream inputStream) {
36 | super.setInputStream(inputStream);
37 | chunkSize = -1;
38 | }
39 |
40 | public void setBuffer (byte[] bytes, int offset, int count) {
41 | super.setBuffer(bytes, offset, count);
42 | chunkSize = -1;
43 | }
44 |
45 | public void rewind () {
46 | super.rewind();
47 | chunkSize = -1;
48 | }
49 |
50 | protected int fill (byte[] buffer, int offset, int count) throws KryoException {
51 | if (chunkSize == -1) // No current chunk, expect a new chunk.
52 | readChunkSize();
53 | else if (chunkSize == 0) // End of chunks.
54 | return -1;
55 | int actual = super.fill(buffer, offset, Math.min(chunkSize, count));
56 | chunkSize -= actual;
57 | if (chunkSize == 0) readChunkSize(); // Read next chunk size.
58 | return actual;
59 | }
60 |
61 | private void readChunkSize () {
62 | try {
63 | InputStream inputStream = getInputStream();
64 | for (int offset = 0, result = 0; offset < 32; offset += 7) {
65 | int b = inputStream.read();
66 | if (b == -1) throw new KryoException("Buffer underflow.");
67 | result |= (b & 0x7F) << offset;
68 | if ((b & 0x80) == 0) {
69 | chunkSize = result;
70 | if (TRACE) trace("kryo", "Read chunk: " + chunkSize);
71 | return;
72 | }
73 | }
74 | } catch (IOException ex) {
75 | throw new KryoException(ex);
76 | }
77 | throw new KryoException("Malformed integer.");
78 | }
79 |
80 | /** Advances the stream to the next set of chunks. InputChunked will appear to hit the end of the data until this method is
81 | * called. */
82 | public void nextChunks () {
83 | if (chunkSize == -1) readChunkSize(); // No current chunk, expect a new chunk.
84 | while (chunkSize > 0)
85 | skip(chunkSize);
86 | chunkSize = -1;
87 | if (TRACE) trace("kryo", "Next chunks.");
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/OutputChunked.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.OutputStream;
6 |
7 | import com.esotericsoftware.kryo.KryoException;
8 |
9 | import static com.esotericsoftware.minlog.Log.*;
10 |
11 | /** An OutputStream that buffers data in a byte array and flushes to another OutputStream, writing the length before each flush.
12 | * The length allows the chunks to be skipped when reading.
13 | * @author Nathan Sweet */
14 | public class OutputChunked extends Output {
15 | /** Creates an uninitialized OutputChunked with a maximum chunk size of 2048. The OutputStream must be set before it can be
16 | * used. */
17 | public OutputChunked () {
18 | super(2048);
19 | }
20 |
21 | /** Creates an uninitialized OutputChunked. The OutputStream must be set before it can be used.
22 | * @param bufferSize The maximum size of a chunk. */
23 | public OutputChunked (int bufferSize) {
24 | super(bufferSize);
25 | }
26 |
27 | /** Creates an OutputChunked with a maximum chunk size of 2048. */
28 | public OutputChunked (OutputStream outputStream) {
29 | super(outputStream, 2048);
30 | }
31 |
32 | /** @param bufferSize The maximum size of a chunk. */
33 | public OutputChunked (OutputStream outputStream, int bufferSize) {
34 | super(outputStream, bufferSize);
35 | }
36 |
37 | public void flush () throws KryoException {
38 | if (position() > 0) {
39 | try {
40 | writeChunkSize();
41 | } catch (IOException ex) {
42 | throw new KryoException(ex);
43 | }
44 | }
45 | super.flush();
46 | }
47 |
48 | private void writeChunkSize () throws IOException {
49 | int size = position();
50 | if (TRACE) trace("kryo", "Write chunk: " + size);
51 | OutputStream outputStream = getOutputStream();
52 | if ((size & ~0x7F) == 0) {
53 | outputStream.write(size);
54 | return;
55 | }
56 | outputStream.write((size & 0x7F) | 0x80);
57 | size >>>= 7;
58 | if ((size & ~0x7F) == 0) {
59 | outputStream.write(size);
60 | return;
61 | }
62 | outputStream.write((size & 0x7F) | 0x80);
63 | size >>>= 7;
64 | if ((size & ~0x7F) == 0) {
65 | outputStream.write(size);
66 | return;
67 | }
68 | outputStream.write((size & 0x7F) | 0x80);
69 | size >>>= 7;
70 | if ((size & ~0x7F) == 0) {
71 | outputStream.write(size);
72 | return;
73 | }
74 | outputStream.write((size & 0x7F) | 0x80);
75 | size >>>= 7;
76 | outputStream.write(size);
77 | }
78 |
79 | /** Marks the end of some data that may have been written by any number of chunks. These chunks can then be skipped when
80 | * reading. */
81 | public void endChunks () {
82 | flush(); // Flush any partial chunk.
83 | if (TRACE) trace("kryo", "End chunks.");
84 | try {
85 | getOutputStream().write(0); // Zero length chunk.
86 | } catch (IOException ex) {
87 | throw new KryoException(ex);
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/UnsafeInput.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 |
7 | import com.esotericsoftware.kryo.KryoException;
8 | import com.esotericsoftware.kryo.util.UnsafeUtil;
9 |
10 | import static com.esotericsoftware.kryo.util.UnsafeUtil.*;
11 |
12 | /** An optimized InputStream that reads data from a byte array and optionally fills the byte array from another InputStream as
13 | * needed. Utility methods are provided for efficiently writing primitive types, arrays of primitive types and strings. It uses
14 | * @link{java.misc.Unsafe} to achieve a very good performance.
15 | *
16 | *
17 | * Important notes:
18 | *
Bulk operations, e.g. on arrays of primitive types, are always using native byte order.
19 | *
Fixed-size int, long, short, float and double elements are always read using native byte order.
20 | *
Best performance is achieved if no variable length encoding for integers is used.
21 | *
Serialized representation used as input for this class should always be produced using @link{UnsafeOutput}
22 | *
23 | * @author Roman Levenstein */
24 | public final class UnsafeInput extends Input {
25 |
26 | private boolean varIntsEnabled = false;
27 |
28 | /** Creates an uninitialized Input. {@link #setBuffer(byte[], int, int)} must be called before the Input is used. */
29 | public UnsafeInput () {
30 | }
31 |
32 | /** Creates a new Input for reading from a byte array.
33 | * @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
34 | public UnsafeInput (int bufferSize) {
35 | super(bufferSize);
36 | }
37 |
38 | /** Creates a new Input for reading from a byte array.
39 | * @see #setBuffer(byte[]) */
40 | public UnsafeInput (byte[] buffer) {
41 | super(buffer);
42 | }
43 |
44 | /** Creates a new Input for reading from a byte array.
45 | * @see #setBuffer(byte[], int, int) */
46 | public UnsafeInput (byte[] buffer, int offset, int count) {
47 | super(buffer, offset, count);
48 | }
49 |
50 | /** Creates a new Input for reading from an InputStream. A buffer size of 4096 is used. */
51 | public UnsafeInput (InputStream inputStream) {
52 | super(inputStream);
53 | }
54 |
55 | /** Creates a new Input for reading from an InputStream. */
56 | public UnsafeInput (InputStream inputStream, int bufferSize) {
57 | super(inputStream, bufferSize);
58 | }
59 |
60 | // int
61 |
62 | /** Reads a 4 byte int. */
63 | public int readInt () throws KryoException {
64 | require(4);
65 | int result = unsafe().getInt(buffer, byteArrayBaseOffset + position);
66 | position += 4;
67 | return result;
68 | }
69 |
70 | // float
71 |
72 | /** Reads a 4 byte float. */
73 | public float readFloat () throws KryoException {
74 | require(4);
75 | float result = unsafe().getFloat(buffer, byteArrayBaseOffset + position);
76 | position += 4;
77 | return result;
78 | }
79 |
80 | // short
81 |
82 | /** Reads a 2 byte short. */
83 | public short readShort () throws KryoException {
84 | require(2);
85 | short result = unsafe().getShort(buffer, byteArrayBaseOffset + position);
86 | position += 2;
87 | return result;
88 | }
89 |
90 | // long
91 |
92 | /** Reads an 8 byte long. */
93 | public long readLong () throws KryoException {
94 | require(8);
95 | long result = unsafe().getLong(buffer, byteArrayBaseOffset + position);
96 | position += 8;
97 | return result;
98 | }
99 |
100 | // double
101 |
102 | /** Writes an 8 byte double. */
103 | public double readDouble () throws KryoException {
104 | require(8);
105 | double result = unsafe().getDouble(buffer, byteArrayBaseOffset + position);
106 | position += 8;
107 | return result;
108 | }
109 |
110 | public int readInt (boolean optimizePositive) throws KryoException {
111 | if (!varIntsEnabled)
112 | return readInt();
113 | else
114 | return super.readInt(optimizePositive);
115 | }
116 |
117 | public long readLong (boolean optimizePositive) throws KryoException {
118 | if (!varIntsEnabled)
119 | return readLong();
120 | else
121 | return super.readLong(optimizePositive);
122 | }
123 |
124 | // Methods implementing bulk operations on arrays of primitive types
125 |
126 | /** {@inheritDoc} */
127 | final public int[] readInts (int length, boolean optimizePositive) throws KryoException {
128 | if (!varIntsEnabled) {
129 | int bytesToCopy = length << 2;
130 | int[] array = new int[length];
131 | readBytes(array, intArrayBaseOffset, 0, bytesToCopy);
132 | return array;
133 | } else
134 | return super.readInts(length, optimizePositive);
135 | }
136 |
137 | /** {@inheritDoc} */
138 | final public long[] readLongs (int length, boolean optimizePositive) throws KryoException {
139 | if (!varIntsEnabled) {
140 | int bytesToCopy = length << 3;
141 | long[] array = new long[length];
142 | readBytes(array, longArrayBaseOffset, 0, bytesToCopy);
143 | return array;
144 | } else
145 | return super.readLongs(length, optimizePositive);
146 | }
147 |
148 | /** {@inheritDoc} */
149 | final public int[] readInts (int length) throws KryoException {
150 | int bytesToCopy = length << 2;
151 | int[] array = new int[length];
152 | readBytes(array, intArrayBaseOffset, 0, bytesToCopy);
153 | return array;
154 | }
155 |
156 | /** {@inheritDoc} */
157 | final public long[] readLongs (int length) throws KryoException {
158 | int bytesToCopy = length << 3;
159 | long[] array = new long[length];
160 | readBytes(array, longArrayBaseOffset, 0, bytesToCopy);
161 | return array;
162 | }
163 |
164 | /** {@inheritDoc} */
165 | final public float[] readFloats (int length) throws KryoException {
166 | int bytesToCopy = length << 2;
167 | float[] array = new float[length];
168 | readBytes(array, floatArrayBaseOffset, 0, bytesToCopy);
169 | return array;
170 | }
171 |
172 | /** {@inheritDoc} */
173 | final public short[] readShorts (int length) throws KryoException {
174 | int bytesToCopy = length << 1;
175 | short[] array = new short[length];
176 | readBytes(array, shortArrayBaseOffset, 0, bytesToCopy);
177 | return array;
178 | }
179 |
180 | /** {@inheritDoc} */
181 | final public char[] readChars (int length) throws KryoException {
182 | int bytesToCopy = length << 1;
183 | char[] array = new char[length];
184 | readBytes(array, charArrayBaseOffset, 0, bytesToCopy);
185 | return array;
186 | }
187 |
188 | /** {@inheritDoc} */
189 | final public double[] readDoubles (int length) throws KryoException {
190 | int bytesToCopy = length << 3;
191 | double[] array = new double[length];
192 | readBytes(array, doubleArrayBaseOffset, 0, bytesToCopy);
193 | return array;
194 | }
195 |
196 | final public void readBytes (Object dstObj, long offset, long count) throws KryoException {
197 | // Unsafe supports efficient bulk reading into arrays of primitives only because
198 | // of JVM limitations due to GC
199 | if (dstObj.getClass().isArray())
200 | readBytes(dstObj, 0, offset, (int)count);
201 | else {
202 | throw new KryoException("Only bulk reads of arrays is supported");
203 | }
204 | }
205 |
206 | final private void readBytes (Object dstArray, long dstArrayTypeOffset, long offset, int count) throws KryoException {
207 | int copyCount = Math.min(limit - position, count);
208 | while (true) {
209 | unsafe().copyMemory(buffer, byteArrayBaseOffset + position, dstArray, dstArrayTypeOffset + offset, copyCount);
210 | position += copyCount;
211 | count -= copyCount;
212 | if (count == 0) break;
213 | offset += copyCount;
214 | copyCount = Math.min(count, capacity);
215 | require(copyCount);
216 | }
217 | }
218 |
219 | /*** Return current setting for variable length encoding of integers
220 | * @return current setting for variable length encoding of integers */
221 | public boolean getVarIntsEnabled () {
222 | return varIntsEnabled;
223 | }
224 |
225 | /*** Controls if a variable length encoding for integer types should be used when serializers suggest it.
226 | *
227 | * @param varIntsEnabled */
228 | public void setVarIntsEnabled (boolean varIntsEnabled) {
229 | this.varIntsEnabled = varIntsEnabled;
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/io/UnsafeMemoryInput.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.io;
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.nio.ByteBuffer;
7 |
8 | import sun.nio.ch.DirectBuffer;
9 |
10 | import com.esotericsoftware.kryo.KryoException;
11 | import static com.esotericsoftware.kryo.util.UnsafeUtil.*;
12 |
13 | /** An optimized InputStream that reads data directly from the off-heap memory. Utility methods are provided for efficiently
14 | * reading primitive types, arrays of primitive types and strings. It uses @link{java.misc.Unsafe} to achieve a very good
15 | * performance.
16 | *
17 | *
18 | * Important notes:
19 | *
Bulk operations, e.g. on arrays of primitive types, are always using native byte order.
20 | *
Fixed-size int, long, short, float and double elements are always read using native byte order.
21 | *
Best performance is achieved if no variable length encoding for integers is used.
22 | *
Serialized representation used as input for this class should always be produced using @link{UnsafeMemoryOutput}
23 | *
24 | * @author Roman Levenstein */
25 | public final class UnsafeMemoryInput extends ByteBufferInput {
26 | /** Start address of the memory buffer The memory buffer should be non-movable, which normally means that is is allocated
27 | * off-heap */
28 | private long bufaddress;
29 |
30 | {
31 | varIntsEnabled = false;
32 |
33 | }
34 |
35 | /** Creates an uninitialized Input. {@link #setBuffer(byte[], int, int)} must be called before the Input is used. */
36 | public UnsafeMemoryInput () {
37 | }
38 |
39 | /** Creates a new Input for reading from a byte array.
40 | * @param bufferSize The initial and maximum size of the buffer. An exception is thrown if this size is exceeded. */
41 | public UnsafeMemoryInput (int bufferSize) {
42 | super(bufferSize);
43 | updateBufferAddress();
44 | }
45 |
46 | /** Creates a new Input for reading from a byte array.
47 | * @see #setBuffer(byte[]) */
48 | public UnsafeMemoryInput (byte[] buffer) {
49 | super(buffer);
50 | updateBufferAddress();
51 | }
52 |
53 | public UnsafeMemoryInput (ByteBuffer buffer) {
54 | super(buffer, 0, buffer.position());
55 | updateBufferAddress();
56 | }
57 |
58 | public UnsafeMemoryInput (long address, int maxBufferSize) {
59 | super(address, maxBufferSize);
60 | updateBufferAddress();
61 | }
62 |
63 | /** Creates a new Input for reading from an InputStream. A buffer size of 4096 is used. */
64 | public UnsafeMemoryInput (InputStream inputStream) {
65 | super(inputStream);
66 | updateBufferAddress();
67 | }
68 |
69 | /** Creates a new Input for reading from an InputStream. */
70 | public UnsafeMemoryInput (InputStream inputStream, int bufferSize) {
71 | super(inputStream, bufferSize);
72 | updateBufferAddress();
73 | }
74 |
75 | public void setBuffer (ByteBuffer buffer, int offset, int count) {
76 | super.setBuffer(buffer, offset, count);
77 | updateBufferAddress();
78 | }
79 |
80 | private void updateBufferAddress () {
81 | bufaddress = ((DirectBuffer)super.niobuffer).address();
82 | }
83 |
84 | /** Reads a 4 byte int. */
85 | public int readInt () throws KryoException {
86 | require(4);
87 | int result = unsafe().getInt(bufaddress + position);
88 | position += 4;
89 | return result;
90 | }
91 |
92 | /** Reads a 4 byte float. */
93 | public float readFloat () throws KryoException {
94 | require(4);
95 | float result = unsafe().getFloat(bufaddress + position);
96 | position += 4;
97 | return result;
98 | }
99 |
100 | /** Reads a 2 byte short. */
101 | public short readShort () throws KryoException {
102 | require(2);
103 | short result = unsafe().getShort(bufaddress + position);
104 | position += 2;
105 | return result;
106 | }
107 |
108 | /** Reads an 8 byte long. */
109 | public long readLong () throws KryoException {
110 | require(8);
111 | long result = unsafe().getLong(bufaddress + position);
112 | position += 8;
113 | return result;
114 | }
115 |
116 | /** Reads a 1 byte boolean. */
117 | public boolean readBoolean () throws KryoException {
118 | super.niobuffer.position(position);
119 | return super.readBoolean();
120 | }
121 |
122 | /** Reads a single byte. */
123 | public byte readByte () throws KryoException {
124 | super.niobuffer.position(position);
125 | return super.readByte();
126 | }
127 |
128 | /** Reads a 2 byte char. */
129 | public char readChar () throws KryoException {
130 | super.niobuffer.position(position);
131 | return super.readChar();
132 | }
133 |
134 | /** Reads an 8 byte double. */
135 | public double readDouble () throws KryoException {
136 | require(8);
137 | double result = unsafe().getDouble(bufaddress + position);
138 | position += 8;
139 | return result;
140 | }
141 |
142 | public int readInt (boolean optimizePositive) throws KryoException {
143 | if (!varIntsEnabled)
144 | return readInt();
145 | else
146 | return super.readInt(optimizePositive);
147 | }
148 |
149 | public long readLong (boolean optimizePositive) throws KryoException {
150 | if (!varIntsEnabled)
151 | return readLong();
152 | else
153 | return super.readLong(optimizePositive);
154 | }
155 |
156 | // Methods implementing bulk operations on arrays of primitive types
157 |
158 | /** {@inheritDoc} */
159 | final public int[] readInts (int length, boolean optimizePositive) throws KryoException {
160 | if (!varIntsEnabled) {
161 | int bytesToCopy = length << 2;
162 | int[] array = new int[length];
163 | readBytes(array, intArrayBaseOffset, 0, bytesToCopy);
164 | return array;
165 | } else
166 | return super.readInts(length, optimizePositive);
167 | }
168 |
169 | /** {@inheritDoc} */
170 | final public long[] readLongs (int length, boolean optimizePositive) throws KryoException {
171 | if (!varIntsEnabled) {
172 | int bytesToCopy = length << 3;
173 | long[] array = new long[length];
174 | readBytes(array, longArrayBaseOffset, 0, bytesToCopy);
175 | return array;
176 | } else
177 | return super.readLongs(length, optimizePositive);
178 | }
179 |
180 | /** {@inheritDoc} */
181 | final public float[] readFloats (int length) throws KryoException {
182 | int bytesToCopy = length << 2;
183 | float[] array = new float[length];
184 | readBytes(array, floatArrayBaseOffset, 0, bytesToCopy);
185 | return array;
186 | }
187 |
188 | /** {@inheritDoc} */
189 | final public short[] readShorts (int length) throws KryoException {
190 | int bytesToCopy = length << 1;
191 | short[] array = new short[length];
192 | readBytes(array, shortArrayBaseOffset, 0, bytesToCopy);
193 | return array;
194 | }
195 |
196 | /** {@inheritDoc} */
197 | final public char[] readChars (int length) throws KryoException {
198 | int bytesToCopy = length << 1;
199 | char[] array = new char[length];
200 | readBytes(array, charArrayBaseOffset, 0, bytesToCopy);
201 | return array;
202 | }
203 |
204 | /** {@inheritDoc} */
205 | final public double[] readDoubles (int length) throws KryoException {
206 | int bytesToCopy = length << 2;
207 | double[] array = new double[length];
208 | readBytes(array, doubleArrayBaseOffset, 0, bytesToCopy);
209 | return array;
210 | }
211 |
212 | final public void readBytes (Object dstObj, long offset, long count) throws KryoException {
213 | /* Unsafe supports efficient bulk reading into arrays of primitives only because of JVM limitations due to GC */
214 | if (dstObj.getClass().isArray())
215 | readBytes(dstObj, 0, offset, (int)count);
216 | else {
217 | throw new KryoException("Only bulk reads of arrays is supported");
218 | }
219 | }
220 |
221 | final private void readBytes (Object dstObj, long dstArrayTypeOffset, long offset, int count) throws KryoException {
222 | int copyCount = Math.min(limit - position, count);
223 | while (true) {
224 | unsafe().copyMemory(null, bufaddress + position, dstObj, dstArrayTypeOffset + offset, copyCount);
225 | position += copyCount;
226 | count -= copyCount;
227 | if (count == 0) break;
228 | offset += copyCount;
229 | copyCount = Math.min(count, capacity);
230 | require(copyCount);
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/AsmCacheFields.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo.serializers;
2 |
3 | import com.esotericsoftware.kryo.Kryo;
4 | import com.esotericsoftware.kryo.KryoException;
5 | import com.esotericsoftware.kryo.io.Input;
6 | import com.esotericsoftware.kryo.io.Output;
7 | import com.esotericsoftware.kryo.serializers.FieldSerializer.CachedField;
8 | import com.esotericsoftware.reflectasm.FieldAccess;
9 |
10 | /*** Implementations of ASM-based serializers for fields.
11 | *
12 | * @author Nathan Sweet */
13 | public class AsmCacheFields {
14 |
15 | abstract static class AsmCachedField extends CachedField {
16 | }
17 |
18 | final static class AsmIntField extends AsmCachedField {
19 | public void write (Output output, Object object) {
20 | if (varIntsEnabled)
21 | output.writeInt(access.getInt(object, accessIndex), false);
22 | else
23 | output.writeInt(access.getInt(object, accessIndex));
24 | }
25 |
26 | public void read (Input input, Object object) {
27 | if (varIntsEnabled)
28 | access.setInt(object, accessIndex, input.readInt(false));
29 | else
30 | access.setInt(object, accessIndex, input.readInt());
31 | }
32 |
33 | public void copy (Object original, Object copy) {
34 | access.setInt(copy, accessIndex, access.getInt(original, accessIndex));
35 | }
36 | }
37 |
38 | final static class AsmFloatField extends AsmCachedField {
39 | public void write (Output output, Object object) {
40 | output.writeFloat(access.getFloat(object, accessIndex));
41 | }
42 |
43 | public void read (Input input, Object object) {
44 | access.setFloat(object, accessIndex, input.readFloat());
45 | }
46 |
47 | public void copy (Object original, Object copy) {
48 | access.setFloat(copy, accessIndex, access.getFloat(original, accessIndex));
49 | }
50 | }
51 |
52 | final static class AsmShortField extends AsmCachedField {
53 | public void write (Output output, Object object) {
54 | output.writeShort(access.getShort(object, accessIndex));
55 | }
56 |
57 | public void read (Input input, Object object) {
58 | access.setShort(object, accessIndex, input.readShort());
59 | }
60 |
61 | public void copy (Object original, Object copy) {
62 | access.setShort(copy, accessIndex, access.getShort(original, accessIndex));
63 | }
64 | }
65 |
66 | final static class AsmByteField extends AsmCachedField {
67 | public void write (Output output, Object object) {
68 | output.writeByte(access.getByte(object, accessIndex));
69 | }
70 |
71 | public void read (Input input, Object object) {
72 | access.setByte(object, accessIndex, input.readByte());
73 | }
74 |
75 | public void copy (Object original, Object copy) {
76 | access.setByte(copy, accessIndex, access.getByte(original, accessIndex));
77 | }
78 | }
79 |
80 | final static class AsmBooleanField extends AsmCachedField {
81 | public void write (Output output, Object object) {
82 | output.writeBoolean(access.getBoolean(object, accessIndex));
83 | }
84 |
85 | public void read (Input input, Object object) {
86 | access.setBoolean(object, accessIndex, input.readBoolean());
87 | }
88 |
89 | public void copy (Object original, Object copy) {
90 | access.setBoolean(copy, accessIndex, access.getBoolean(original, accessIndex));
91 | }
92 | }
93 |
94 | final static class AsmCharField extends AsmCachedField {
95 | public void write (Output output, Object object) {
96 | output.writeChar(access.getChar(object, accessIndex));
97 | }
98 |
99 | public void read (Input input, Object object) {
100 | access.setChar(object, accessIndex, input.readChar());
101 | }
102 |
103 | public void copy (Object original, Object copy) {
104 | access.setChar(copy, accessIndex, access.getChar(original, accessIndex));
105 | }
106 | }
107 |
108 | final static class AsmLongField extends AsmCachedField {
109 | public void write (Output output, Object object) {
110 | if (varIntsEnabled)
111 | output.writeLong(access.getLong(object, accessIndex), false);
112 | else
113 | output.writeLong(access.getLong(object, accessIndex));
114 | }
115 |
116 | public void read (Input input, Object object) {
117 | if (varIntsEnabled)
118 | access.setLong(object, accessIndex, input.readLong(false));
119 | else
120 | access.setLong(object, accessIndex, input.readLong());
121 | }
122 |
123 | public void copy (Object original, Object copy) {
124 | access.setLong(copy, accessIndex, access.getLong(original, accessIndex));
125 | }
126 | }
127 |
128 | final static class AsmDoubleField extends AsmCachedField {
129 | public void write (Output output, Object object) {
130 | output.writeDouble(access.getDouble(object, accessIndex));
131 | }
132 |
133 | public void read (Input input, Object object) {
134 | access.setDouble(object, accessIndex, input.readDouble());
135 | }
136 |
137 | public void copy (Object original, Object copy) {
138 | access.setDouble(copy, accessIndex, access.getDouble(original, accessIndex));
139 | }
140 | }
141 |
142 | final static class AsmStringField extends AsmCachedField {
143 | public void write (Output output, Object object) {
144 | output.writeString(access.getString(object, accessIndex));
145 | }
146 |
147 | public void read (Input input, Object object) {
148 | access.set(object, accessIndex, input.readString());
149 | }
150 |
151 | public void copy (Object original, Object copy) {
152 | access.set(copy, accessIndex, access.getString(original, accessIndex));
153 | }
154 | }
155 |
156 | final static class AsmObjectField extends ObjectField {
157 |
158 | public AsmObjectField (FieldSerializer fieldSerializer) {
159 | super(fieldSerializer);
160 | }
161 |
162 | public Object getField (Object object) throws IllegalArgumentException, IllegalAccessException {
163 | if (accessIndex != -1) return ((FieldAccess)access).get(object, accessIndex);
164 | throw new KryoException("Unknown acess index");
165 | }
166 |
167 | public void setField (Object object, Object value) throws IllegalArgumentException, IllegalAccessException {
168 | if (accessIndex != -1)
169 | ((FieldAccess)access).set(object, accessIndex, value);
170 | else
171 | throw new KryoException("Unknown acess index");
172 | }
173 |
174 | public void copy (Object original, Object copy) {
175 | try {
176 | if (accessIndex != -1) {
177 | access.set(copy, accessIndex, kryo.copy(access.get(original, accessIndex)));
178 | } else
179 | throw new KryoException("Unknown acess index");
180 | } catch (KryoException ex) {
181 | ex.addTrace(this + " (" + type.getName() + ")");
182 | throw ex;
183 | } catch (RuntimeException runtimeEx) {
184 | KryoException ex = new KryoException(runtimeEx);
185 | ex.addTrace(this + " (" + type.getName() + ")");
186 | throw ex;
187 | }
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/AsmCachedFieldFactory.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo.serializers;
2 |
3 | import java.lang.reflect.Field;
4 |
5 | import com.esotericsoftware.kryo.serializers.FieldSerializer.CachedField;
6 | import com.esotericsoftware.kryo.serializers.FieldSerializer.CachedFieldFactory;
7 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmBooleanField;
8 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmByteField;
9 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmCharField;
10 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmDoubleField;
11 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmFloatField;
12 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmIntField;
13 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmLongField;
14 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmShortField;
15 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmStringField;
16 | import com.esotericsoftware.kryo.serializers.AsmCacheFields.AsmObjectField;
17 |
18 | class AsmCachedFieldFactory implements CachedFieldFactory {
19 | public CachedField createCachedField (Class fieldClass, Field field, FieldSerializer ser) {
20 | CachedField cachedField;
21 | // Use ASM-based serializers
22 | if (fieldClass.isPrimitive()) {
23 | if (fieldClass == boolean.class)
24 | cachedField = new AsmBooleanField();
25 | else if (fieldClass == byte.class)
26 | cachedField = new AsmByteField();
27 | else if (fieldClass == char.class)
28 | cachedField = new AsmCharField();
29 | else if (fieldClass == short.class)
30 | cachedField = new AsmShortField();
31 | else if (fieldClass == int.class)
32 | cachedField = new AsmIntField();
33 | else if (fieldClass == long.class)
34 | cachedField = new AsmLongField();
35 | else if (fieldClass == float.class)
36 | cachedField = new AsmFloatField();
37 | else if (fieldClass == double.class)
38 | cachedField = new AsmDoubleField();
39 | else {
40 | cachedField = new AsmObjectField(ser);
41 | }
42 | } else if (fieldClass == String.class
43 | && (!ser.kryo.getReferences() || !ser.kryo.getReferenceResolver().useReferences(String.class))) {
44 | cachedField = new AsmStringField();
45 | } else {
46 | cachedField = new AsmObjectField(ser);
47 | }
48 | return cachedField;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/BeanSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import java.beans.BeanInfo;
5 | import java.beans.IntrospectionException;
6 | import java.beans.Introspector;
7 | import java.beans.PropertyDescriptor;
8 | import java.lang.reflect.InvocationTargetException;
9 | import java.lang.reflect.Method;
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.Comparator;
13 |
14 | import com.esotericsoftware.kryo.Kryo;
15 | import com.esotericsoftware.kryo.KryoException;
16 | import com.esotericsoftware.kryo.Serializer;
17 | import com.esotericsoftware.kryo.io.Input;
18 | import com.esotericsoftware.kryo.io.Output;
19 | import com.esotericsoftware.reflectasm.MethodAccess;
20 |
21 | import static com.esotericsoftware.minlog.Log.*;
22 |
23 | /** Serializes Java beans using bean accessor methods. Only bean properties with both a getter and setter are serialized. This
24 | * class is not as fast as {@link FieldSerializer} but is much faster and more efficient than Java serialization. Bytecode
25 | * generation is used to invoke the bean propert methods, if possible.
26 | *
27 | * BeanSerializer does not write header data, only the object data is stored. If the type of a bean property is not final (note
28 | * primitives are final) then an extra byte is written for that property.
29 | * @see Serializer
30 | * @see Kryo#register(Class, Serializer)
31 | * @author Nathan Sweet */
32 | public class BeanSerializer extends Serializer {
33 | static final Object[] noArgs = {};
34 |
35 | private final Kryo kryo;
36 | private CachedProperty[] properties;
37 | Object access;
38 |
39 | public BeanSerializer (Kryo kryo, Class type) {
40 | this.kryo = kryo;
41 |
42 | BeanInfo info;
43 | try {
44 | info = Introspector.getBeanInfo(type);
45 | } catch (IntrospectionException ex) {
46 | throw new KryoException("Error getting bean info.", ex);
47 | }
48 | // Methods are sorted by alpha so the order of the data is known.
49 | PropertyDescriptor[] descriptors = info.getPropertyDescriptors();
50 | Arrays.sort(descriptors, new Comparator() {
51 | public int compare (PropertyDescriptor o1, PropertyDescriptor o2) {
52 | return o1.getName().compareTo(o2.getName());
53 | }
54 | });
55 | ArrayList cachedProperties = new ArrayList(descriptors.length);
56 | for (int i = 0, n = descriptors.length; i < n; i++) {
57 | PropertyDescriptor property = descriptors[i];
58 | String name = property.getName();
59 | if (name.equals("class")) continue;
60 | Method getMethod = property.getReadMethod();
61 | Method setMethod = property.getWriteMethod();
62 | if (getMethod == null || setMethod == null) continue; // Require both a getter and setter.
63 |
64 | // Always use the same serializer for this property if the properties' class is final.
65 | Serializer serializer = null;
66 | Class returnType = getMethod.getReturnType();
67 | if (kryo.isFinal(returnType)) serializer = kryo.getRegistration(returnType).getSerializer();
68 |
69 | CachedProperty cachedProperty = new CachedProperty();
70 | cachedProperty.name = name;
71 | cachedProperty.getMethod = getMethod;
72 | cachedProperty.setMethod = setMethod;
73 | cachedProperty.serializer = serializer;
74 | cachedProperty.setMethodType = setMethod.getParameterTypes()[0];
75 | cachedProperties.add(cachedProperty);
76 | }
77 |
78 | properties = cachedProperties.toArray(new CachedProperty[cachedProperties.size()]);
79 |
80 | try {
81 | access = MethodAccess.get(type);
82 | for (int i = 0, n = properties.length; i < n; i++) {
83 | CachedProperty property = properties[i];
84 | property.getterAccessIndex = ((MethodAccess)access).getIndex(property.getMethod.getName(),
85 | property.getMethod.getParameterTypes());
86 | property.setterAccessIndex = ((MethodAccess)access).getIndex(property.setMethod.getName(),
87 | property.setMethod.getParameterTypes());
88 | }
89 | } catch (Throwable ignored) {
90 | // ReflectASM is not available on Android.
91 | }
92 | }
93 |
94 | public void write (Kryo kryo, Output output, T object) {
95 | Class type = object.getClass();
96 | for (int i = 0, n = properties.length; i < n; i++) {
97 | CachedProperty property = properties[i];
98 | try {
99 | if (TRACE) trace("kryo", "Write property: " + property + " (" + type.getName() + ")");
100 | Object value = property.get(object);
101 | Serializer serializer = property.serializer;
102 | if (serializer != null)
103 | kryo.writeObjectOrNull(output, value, serializer);
104 | else
105 | kryo.writeClassAndObject(output, value);
106 | } catch (IllegalAccessException ex) {
107 | throw new KryoException("Error accessing getter method: " + property + " (" + type.getName() + ")", ex);
108 | } catch (InvocationTargetException ex) {
109 | throw new KryoException("Error invoking getter method: " + property + " (" + type.getName() + ")", ex);
110 | } catch (KryoException ex) {
111 | ex.addTrace(property + " (" + type.getName() + ")");
112 | throw ex;
113 | } catch (RuntimeException runtimeEx) {
114 | KryoException ex = new KryoException(runtimeEx);
115 | ex.addTrace(property + " (" + type.getName() + ")");
116 | throw ex;
117 | }
118 | }
119 | }
120 |
121 | public T read (Kryo kryo, Input input, Class type) {
122 | T object = kryo.newInstance(type);
123 | kryo.reference(object);
124 | for (int i = 0, n = properties.length; i < n; i++) {
125 | CachedProperty property = properties[i];
126 | try {
127 | if (TRACE) trace("kryo", "Read property: " + property + " (" + object.getClass() + ")");
128 | Object value;
129 | Serializer serializer = property.serializer;
130 | if (serializer != null)
131 | value = kryo.readObjectOrNull(input, property.setMethodType, serializer);
132 | else
133 | value = kryo.readClassAndObject(input);
134 | property.set(object, value);
135 | } catch (IllegalAccessException ex) {
136 | throw new KryoException("Error accessing setter method: " + property + " (" + object.getClass().getName() + ")", ex);
137 | } catch (InvocationTargetException ex) {
138 | throw new KryoException("Error invoking setter method: " + property + " (" + object.getClass().getName() + ")", ex);
139 | } catch (KryoException ex) {
140 | ex.addTrace(property + " (" + object.getClass().getName() + ")");
141 | throw ex;
142 | } catch (RuntimeException runtimeEx) {
143 | KryoException ex = new KryoException(runtimeEx);
144 | ex.addTrace(property + " (" + object.getClass().getName() + ")");
145 | throw ex;
146 | }
147 | }
148 | return object;
149 | }
150 |
151 | public T copy (Kryo kryo, T original) {
152 | T copy = (T)kryo.newInstance(original.getClass());
153 | for (int i = 0, n = properties.length; i < n; i++) {
154 | CachedProperty property = properties[i];
155 | try {
156 | Object value = property.get(original);
157 | property.set(copy, value);
158 | } catch (KryoException ex) {
159 | ex.addTrace(property + " (" + copy.getClass().getName() + ")");
160 | throw ex;
161 | } catch (RuntimeException runtimeEx) {
162 | KryoException ex = new KryoException(runtimeEx);
163 | ex.addTrace(property + " (" + copy.getClass().getName() + ")");
164 | throw ex;
165 | } catch (Exception ex) {
166 | throw new KryoException("Error copying bean property: " + property + " (" + copy.getClass().getName() + ")", ex);
167 | }
168 | }
169 | return copy;
170 | }
171 |
172 | class CachedProperty {
173 | String name;
174 | Method getMethod, setMethod;
175 | Class setMethodType;
176 | Serializer serializer;
177 | int getterAccessIndex, setterAccessIndex;
178 |
179 | public String toString () {
180 | return name;
181 | }
182 |
183 | Object get (Object object) throws IllegalAccessException, InvocationTargetException {
184 | if (access != null) return ((MethodAccess)access).invoke(object, getterAccessIndex);
185 | return getMethod.invoke(object, noArgs);
186 | }
187 |
188 | void set (Object object, Object value) throws IllegalAccessException, InvocationTargetException {
189 | if (access != null) {
190 | ((MethodAccess)access).invoke(object, setterAccessIndex, value);
191 | return;
192 | }
193 | setMethod.invoke(object, new Object[] {value});
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/BlowfishSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import java.io.IOException;
5 |
6 | import javax.crypto.Cipher;
7 | import javax.crypto.CipherInputStream;
8 | import javax.crypto.CipherOutputStream;
9 | import javax.crypto.spec.SecretKeySpec;
10 |
11 | import com.esotericsoftware.kryo.Kryo;
12 | import com.esotericsoftware.kryo.KryoException;
13 | import com.esotericsoftware.kryo.Serializer;
14 | import com.esotericsoftware.kryo.io.Input;
15 | import com.esotericsoftware.kryo.io.Output;
16 |
17 | /** Encrypts data using the blowfish cipher.
18 | * @author Nathan Sweet */
19 | public class BlowfishSerializer extends Serializer {
20 | private final Serializer serializer;
21 | static private SecretKeySpec keySpec;
22 |
23 | public BlowfishSerializer (Serializer serializer, byte[] key) {
24 | this.serializer = serializer;
25 | keySpec = new SecretKeySpec(key, "Blowfish");
26 | }
27 |
28 | public void write (Kryo kryo, Output output, Object object) {
29 | Cipher cipher = getCipher(Cipher.ENCRYPT_MODE);
30 | CipherOutputStream cipherStream = new CipherOutputStream(output, cipher);
31 | Output cipherOutput = new Output(cipherStream, 256) {
32 | public void close () throws KryoException {
33 | // Don't allow the CipherOutputStream to close the output.
34 | }
35 | };
36 | kryo.writeObject(cipherOutput, object, serializer);
37 | cipherOutput.flush();
38 | try {
39 | cipherStream.close();
40 | } catch (IOException ex) {
41 | throw new KryoException(ex);
42 | }
43 | }
44 |
45 | public Object read (Kryo kryo, Input input, Class type) {
46 | Cipher cipher = getCipher(Cipher.DECRYPT_MODE);
47 | CipherInputStream cipherInput = new CipherInputStream(input, cipher);
48 | return kryo.readObject(new Input(cipherInput, 256), type, serializer);
49 | }
50 |
51 | public Object copy (Kryo kryo, Object original) {
52 | return serializer.copy(kryo, original);
53 | }
54 |
55 | static private Cipher getCipher (int mode) {
56 | try {
57 | Cipher cipher = Cipher.getInstance("Blowfish");
58 | cipher.init(mode, keySpec);
59 | return cipher;
60 | } catch (Exception ex) {
61 | throw new KryoException(ex);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/CollectionSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import java.util.ArrayList;
5 | import java.util.Collection;
6 |
7 | import com.esotericsoftware.kryo.Kryo;
8 | import com.esotericsoftware.kryo.Serializer;
9 | import com.esotericsoftware.kryo.io.Input;
10 | import com.esotericsoftware.kryo.io.Output;
11 |
12 | /** Serializes objects that implement the {@link Collection} interface.
13 | *
14 | * 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
15 | * collection. The alternate constructor can be used to improve efficiency to match that of using an array instead of a
16 | * collection.
17 | * @author Nathan Sweet */
18 | public class CollectionSerializer extends Serializer {
19 | private boolean elementsCanBeNull = true;
20 | private Serializer serializer;
21 | private Class elementClass;
22 | private Class genericType;
23 |
24 | public CollectionSerializer () {
25 | }
26 |
27 | /** @see #setElementClass(Class, Serializer) */
28 | public CollectionSerializer (Class elementClass, Serializer serializer) {
29 | setElementClass(elementClass, serializer);
30 | }
31 |
32 | /** @see #setElementClass(Class, Serializer)
33 | * @see #setElementsCanBeNull(boolean) */
34 | public CollectionSerializer (Class elementClass, Serializer serializer, boolean elementsCanBeNull) {
35 | setElementClass(elementClass, serializer);
36 | this.elementsCanBeNull = elementsCanBeNull;
37 | }
38 |
39 | /** @param elementsCanBeNull False if all elements are not null. This saves 1 byte per element if elementClass is set. True if it
40 | * is not known (default). */
41 | public void setElementsCanBeNull (boolean elementsCanBeNull) {
42 | this.elementsCanBeNull = elementsCanBeNull;
43 | }
44 |
45 | /** @param elementClass The concrete class of each element. This saves 1-2 bytes per element. Set to null if the class is not
46 | * known or varies per element (default).
47 | * @param serializer The serializer to use for each element. */
48 | public void setElementClass (Class elementClass, Serializer serializer) {
49 | this.elementClass = elementClass;
50 | this.serializer = serializer;
51 | }
52 |
53 | public void setGenerics (Kryo kryo, Class[] generics) {
54 | genericType = null;
55 | if (generics != null && generics.length > 0) {
56 | if (kryo.isFinal(generics[0])) genericType = generics[0];
57 | }
58 | }
59 |
60 | public void write (Kryo kryo, Output output, Collection collection) {
61 | int length = collection.size();
62 | output.writeVarInt(length, true);
63 | Serializer serializer = this.serializer;
64 | if (genericType != null) {
65 | if (serializer == null) serializer = kryo.getSerializer(genericType);
66 | genericType = null;
67 | }
68 | if (serializer != null) {
69 | if (elementsCanBeNull) {
70 | for (Object element : collection)
71 | kryo.writeObjectOrNull(output, element, serializer);
72 | } else {
73 | for (Object element : collection)
74 | kryo.writeObject(output, element, serializer);
75 | }
76 | } else {
77 | for (Object element : collection)
78 | kryo.writeClassAndObject(output, element);
79 | }
80 | }
81 |
82 | /** Used by {@link #read(Kryo, Input, Class)} to create the new object. This can be overridden to customize object creation, eg
83 | * to call a constructor with arguments. The default implementation uses {@link Kryo#newInstance(Class)}. */
84 | protected Collection create (Kryo kryo, Input input, Class type) {
85 | return kryo.newInstance(type);
86 | }
87 |
88 | public Collection read (Kryo kryo, Input input, Class type) {
89 | Collection collection = create(kryo, input, type);
90 | kryo.reference(collection);
91 | int length = input.readVarInt(true);
92 | if (collection instanceof ArrayList) ((ArrayList)collection).ensureCapacity(length);
93 | Class elementClass = this.elementClass;
94 | Serializer serializer = this.serializer;
95 | if (genericType != null) {
96 | if (serializer == null) {
97 | elementClass = genericType;
98 | serializer = kryo.getSerializer(genericType);
99 | }
100 | genericType = null;
101 | }
102 | if (serializer != null) {
103 | if (elementsCanBeNull) {
104 | for (int i = 0; i < length; i++)
105 | collection.add(kryo.readObjectOrNull(input, elementClass, serializer));
106 | } else {
107 | for (int i = 0; i < length; i++)
108 | collection.add(kryo.readObject(input, elementClass, serializer));
109 | }
110 | } else {
111 | for (int i = 0; i < length; i++)
112 | collection.add(kryo.readClassAndObject(input));
113 | }
114 | return collection;
115 | }
116 |
117 | /** Used by {@link #copy(Kryo, Collection)} to create the new object. This can be overridden to customize object creation, eg to
118 | * call a constructor with arguments. The default implementation uses {@link Kryo#newInstance(Class)}. */
119 | protected Collection createCopy (Kryo kryo, Collection original) {
120 | return kryo.newInstance(original.getClass());
121 | }
122 |
123 | public Collection copy (Kryo kryo, Collection original) {
124 | Collection copy = createCopy(kryo, original);
125 | kryo.reference(copy);
126 | for (Object element : original)
127 | copy.add(kryo.copy(element));
128 | return copy;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/CompatibleFieldSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import com.esotericsoftware.kryo.Kryo;
5 | import com.esotericsoftware.kryo.io.Input;
6 | import com.esotericsoftware.kryo.io.InputChunked;
7 | import com.esotericsoftware.kryo.io.Output;
8 | import com.esotericsoftware.kryo.io.OutputChunked;
9 | import com.esotericsoftware.kryo.util.ObjectMap;
10 |
11 | import static com.esotericsoftware.minlog.Log.*;
12 |
13 | /** Serializes objects using direct field assignment, with limited support for forward and backward compatibility. Fields can be
14 | * added or removed without invalidating previously serialized bytes. Note that changing the type of a field is not supported.
15 | *
16 | * There is additional overhead compared to {@link FieldSerializer}. A header is output the first time an object of a given type
17 | * is serialized. The header consists of an int for the number of fields, then a String for each field name. Also, to support
18 | * 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
19 | * bytes.
20 | *
21 | * 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
22 | * must be avoided.
23 | * @author Nathan Sweet */
24 | public class CompatibleFieldSerializer extends FieldSerializer {
25 | public CompatibleFieldSerializer (Kryo kryo, Class type) {
26 | super(kryo, type);
27 | }
28 |
29 | public void write (Kryo kryo, Output output, T object) {
30 | CachedField[] fields = getFields();
31 | ObjectMap context = kryo.getGraphContext();
32 | if (!context.containsKey(this)) {
33 | context.put(this, null);
34 | if (TRACE) trace("kryo", "Write " + fields.length + " field names.");
35 | output.writeVarInt(fields.length, true);
36 | for (int i = 0, n = fields.length; i < n; i++)
37 | output.writeString(fields[i].field.getName());
38 | }
39 |
40 | OutputChunked outputChunked = new OutputChunked(output, 1024);
41 | for (int i = 0, n = fields.length; i < n; i++) {
42 | fields[i].write(outputChunked, object);
43 | outputChunked.endChunks();
44 | }
45 | }
46 |
47 | public T read (Kryo kryo, Input input, Class type) {
48 | T object = create(kryo, input, type);
49 | kryo.reference(object);
50 | ObjectMap context = kryo.getGraphContext();
51 | CachedField[] fields = (CachedField[])context.get(this);
52 | if (fields == null) {
53 | int length = input.readVarInt(true);
54 | if (TRACE) trace("kryo", "Read " + length + " field names.");
55 | String[] names = new String[length];
56 | for (int i = 0; i < length; i++)
57 | names[i] = input.readString();
58 |
59 | fields = new CachedField[length];
60 | CachedField[] allFields = getFields();
61 | outer:
62 | for (int i = 0, n = names.length; i < n; i++) {
63 | String schemaName = names[i];
64 | for (int ii = 0, nn = allFields.length; ii < nn; ii++) {
65 | if (allFields[ii].field.getName().equals(schemaName)) {
66 | fields[i] = allFields[ii];
67 | continue outer;
68 | }
69 | }
70 | if (TRACE) trace("kryo", "Ignore obsolete field: " + schemaName);
71 | }
72 | context.put(this, fields);
73 | }
74 |
75 | InputChunked inputChunked = new InputChunked(input, 1024);
76 | for (int i = 0, n = fields.length; i < n; i++) {
77 | CachedField cachedField = fields[i];
78 | if (cachedField == null) {
79 | if (TRACE) trace("kryo", "Skip obsolete field.");
80 | inputChunked.nextChunks();
81 | continue;
82 | }
83 | cachedField.read(inputChunked, object);
84 | inputChunked.nextChunks();
85 | }
86 | return object;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/DeflateSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import java.io.IOException;
5 | import java.util.zip.Deflater;
6 | import java.util.zip.DeflaterOutputStream;
7 | import java.util.zip.Inflater;
8 | import java.util.zip.InflaterInputStream;
9 |
10 | import com.esotericsoftware.kryo.Kryo;
11 | import com.esotericsoftware.kryo.KryoException;
12 | import com.esotericsoftware.kryo.Serializer;
13 | import com.esotericsoftware.kryo.io.Input;
14 | import com.esotericsoftware.kryo.io.InputChunked;
15 | import com.esotericsoftware.kryo.io.Output;
16 | import com.esotericsoftware.kryo.io.OutputChunked;
17 |
18 | public class DeflateSerializer extends Serializer {
19 | private final Serializer serializer;
20 | private boolean noHeaders = true;
21 | private int compressionLevel = 4;
22 |
23 | public DeflateSerializer (Serializer serializer) {
24 | this.serializer = serializer;
25 | }
26 |
27 | public void write (Kryo kryo, Output output, Object object) {
28 | Deflater deflater = new Deflater(compressionLevel, noHeaders);
29 | OutputChunked outputChunked = new OutputChunked(output, 256);
30 | DeflaterOutputStream deflaterStream = new DeflaterOutputStream(outputChunked, deflater);
31 | Output deflaterOutput = new Output(deflaterStream, 256);
32 | kryo.writeObject(deflaterOutput, object, serializer);
33 | deflaterOutput.flush();
34 | try {
35 | deflaterStream.finish();
36 | } catch (IOException ex) {
37 | throw new KryoException(ex);
38 | }
39 | outputChunked.endChunks();
40 | }
41 |
42 | public Object read (Kryo kryo, Input input, Class type) {
43 | // The inflater would read from input beyond the compressed bytes if chunked enoding wasn't used.
44 | InflaterInputStream inflaterStream = new InflaterInputStream(new InputChunked(input, 256), new Inflater(noHeaders));
45 | return kryo.readObject(new Input(inflaterStream, 256), type, serializer);
46 | }
47 |
48 | public void setNoHeaders (boolean noHeaders) {
49 | this.noHeaders = noHeaders;
50 | }
51 |
52 | /** Default is 4.
53 | * @see Deflater#setLevel(int) */
54 | public void setCompressionLevel (int compressionLevel) {
55 | this.compressionLevel = compressionLevel;
56 | }
57 |
58 | public Object copy (Kryo kryo, Object original) {
59 | return serializer.copy(kryo, original);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/FieldSerializerUnsafeUtil.java:
--------------------------------------------------------------------------------
1 | package com.esotericsoftware.kryo.serializers;
2 |
3 | import static com.esotericsoftware.kryo.util.UnsafeUtil.unsafe;
4 | import static com.esotericsoftware.minlog.Log.TRACE;
5 | import static com.esotericsoftware.minlog.Log.trace;
6 |
7 | import java.lang.reflect.Field;
8 | import java.util.List;
9 |
10 | import com.esotericsoftware.kryo.serializers.FieldSerializer.CachedField;
11 | import com.esotericsoftware.kryo.serializers.UnsafeCacheFields.UnsafeRegionField;
12 | import com.esotericsoftware.kryo.util.IntArray;
13 | import com.esotericsoftware.reflectasm.FieldAccess;
14 |
15 | /* Helper class for implementing FieldSerializer using Unsafe-based approach.
16 | * @author Roman Levenstein */
17 | final class FieldSerializerUnsafeUtil {
18 | private FieldSerializer serializer;
19 |
20 | public FieldSerializerUnsafeUtil (FieldSerializer serializer) {
21 | this.serializer = serializer;
22 | }
23 |
24 | /** Use Unsafe-based information about fields layout in memory to build a list of cached fields and memory regions representing
25 | * consecutive fields in memory */
26 | public void createUnsafeCacheFieldsAndRegions (List validFields, List cachedFields, int baseIndex,
27 | IntArray useAsm) {
28 | // Find adjacent fields of primitive types
29 | long startPrimitives = 0;
30 | long endPrimitives = 0;
31 | boolean lastWasPrimitive = false;
32 | int primitiveLength = 0;
33 | int lastAccessIndex = -1;
34 | Field lastField = null;
35 | long fieldOffset = -1;
36 | long fieldEndOffset = -1;
37 | long lastFieldEndOffset = -1;
38 |
39 | for (int i = 0, n = validFields.size(); i < n; i++) {
40 | Field field = validFields.get(i);
41 |
42 | int accessIndex = -1;
43 | if (serializer.access != null && useAsm.get(baseIndex + i) == 1)
44 | accessIndex = ((FieldAccess)serializer.access).getIndex(field.getName());
45 |
46 | fieldOffset = unsafe().objectFieldOffset(field);
47 | fieldEndOffset = fieldOffset + fieldSizeOf(field.getType());
48 |
49 | if (!field.getType().isPrimitive() && lastWasPrimitive) {
50 | // This is not a primitive field. Therefore, it marks
51 | // the end of a region of primitive fields
52 | endPrimitives = lastFieldEndOffset;
53 | lastWasPrimitive = false;
54 | if (primitiveLength > 1) {
55 | if (TRACE)
56 | trace("kryo", "Class " + serializer.getType().getName()
57 | + ". Found a set of consecutive primitive fields. Number of fields = " + primitiveLength
58 | + ". Byte length = " + (endPrimitives - startPrimitives) + " Start offset = " + startPrimitives
59 | + " endOffset=" + endPrimitives);
60 | // TODO: register a region instead of a field
61 | CachedField cf = new UnsafeRegionField(startPrimitives, (endPrimitives - startPrimitives));
62 | cf.field = lastField;
63 | cachedFields.add(cf);
64 | } else {
65 | if (lastField != null)
66 | cachedFields.add(serializer.newCachedField(lastField, cachedFields.size(), lastAccessIndex));
67 | }
68 | cachedFields.add(serializer.newCachedField(field, cachedFields.size(), accessIndex));
69 | } else if (!field.getType().isPrimitive()) {
70 | cachedFields.add(serializer.newCachedField(field, cachedFields.size(), accessIndex));
71 | } else if (!lastWasPrimitive) {
72 | // If previous field was non primitive, it marks a start
73 | // of a region of primitive fields
74 | startPrimitives = fieldOffset;
75 | lastWasPrimitive = true;
76 | primitiveLength = 1;
77 | } else {
78 | primitiveLength++;
79 | }
80 |
81 | lastAccessIndex = accessIndex;
82 | lastField = field;
83 | lastFieldEndOffset = fieldEndOffset;
84 | }
85 |
86 | if (!serializer.getUseAsmEnabled() && serializer.getUseMemRegions() && lastWasPrimitive) {
87 | endPrimitives = lastFieldEndOffset;
88 | if (primitiveLength > 1) {
89 | if (TRACE) {
90 | trace("kryo", "Class " + serializer.getType().getName()
91 | + ". Found a set of consecutive primitive fields. Number of fields = " + primitiveLength + ". Byte length = "
92 | + (endPrimitives - startPrimitives) + " Start offset = " + startPrimitives + " endOffset=" + endPrimitives);
93 | }
94 | // register a region instead of a field
95 | CachedField cf = new UnsafeRegionField(startPrimitives, (endPrimitives - startPrimitives));
96 | cf.field = lastField;
97 | cachedFields.add(cf);
98 | } else {
99 | if (lastField != null) cachedFields.add(serializer.newCachedField(lastField, cachedFields.size(), lastAccessIndex));
100 | }
101 | }
102 | }
103 |
104 | /** Returns the in-memory size of a field which has a given class */
105 | private int fieldSizeOf (Class> clazz) {
106 | if (clazz == int.class || clazz == float.class) return 4;
107 |
108 | if (clazz == long.class || clazz == double.class) return 8;
109 |
110 | if (clazz == byte.class || clazz == boolean.class) return 1;
111 |
112 | if (clazz == short.class || clazz == char.class) return 2;
113 |
114 | // Everything else is a reference to an object, i.e. an address
115 | return unsafe().addressSize();
116 | }
117 |
118 | long getObjectFieldOffset (Field field) {
119 | return unsafe().objectFieldOffset(field);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/JavaSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import java.io.ObjectInputStream;
5 | import java.io.ObjectOutputStream;
6 |
7 | import com.esotericsoftware.kryo.Kryo;
8 | import com.esotericsoftware.kryo.KryoException;
9 | import com.esotericsoftware.kryo.KryoSerializable;
10 | import com.esotericsoftware.kryo.Serializer;
11 | import com.esotericsoftware.kryo.io.Input;
12 | import com.esotericsoftware.kryo.io.Output;
13 |
14 | /** Serializes objects using Java's built in serialization mechanism. Note that this is very inefficient and should be avoided if
15 | * possible.
16 | * @see Serializer
17 | * @see FieldSerializer
18 | * @see KryoSerializable
19 | * @author Nathan Sweet */
20 | public class JavaSerializer extends Serializer {
21 | private ObjectOutputStream objectStream;
22 | private Output lastOutput;
23 |
24 | public void write (Kryo kryo, Output output, Object object) {
25 | try {
26 | if (output != lastOutput) {
27 | objectStream = new ObjectOutputStream(output);
28 | lastOutput = output;
29 | } else
30 | objectStream.reset();
31 | objectStream.writeObject(object);
32 | objectStream.flush();
33 | } catch (Exception ex) {
34 | throw new KryoException("Error during Java serialization.", ex);
35 | }
36 | }
37 |
38 | public Object read (Kryo kryo, Input input, Class type) {
39 | try {
40 | return new ObjectInputStream(input).readObject();
41 | } catch (Exception ex) {
42 | throw new KryoException("Error during Java deserialization.", ex);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/com/esotericsoftware/kryo/serializers/MapSerializer.java:
--------------------------------------------------------------------------------
1 |
2 | package com.esotericsoftware.kryo.serializers;
3 |
4 | import java.util.Iterator;
5 | import java.util.Map;
6 | import java.util.Map.Entry;
7 |
8 | import com.esotericsoftware.kryo.Kryo;
9 | import com.esotericsoftware.kryo.Serializer;
10 | import com.esotericsoftware.kryo.io.Input;
11 | import com.esotericsoftware.kryo.io.Output;
12 |
13 | /** Serializes objects that implement the {@link Map} interface.
14 | *
15 | * With the default constructor, a map requires a 1-3 byte header and an extra 4 bytes is written for each key/value pair.
16 | * @author Nathan Sweet */
17 | public class MapSerializer extends Serializer