Merge pull request #69 from AlbumenJ/merge/hessian4
Merge hessian4 into hessian-lite
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 43cd92a..f870703 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -19,15 +19,11 @@
steps:
- uses: actions/checkout@v3
- - name: Set up JDK 11
+ - name: Set up JDK 8
uses: actions/setup-java@v3
with:
- java-version: '11'
+ java-version: '8'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --file pom.xml
-
- # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive
- - name: Update dependency graph
- uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6
diff --git a/NOTICE b/NOTICE
index 1e0f705..2744a49 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
Apache Dubbo
-Copyright 2021 The Apache Software Foundation
+Copyright 2018-2024 The Apache Software Foundation
This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/pom.xml b/pom.xml
index eba1164..74df34a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,15 +19,15 @@
<modelVersion>4.0.0</modelVersion>
<parent>
- <groupId>org.sonatype.oss</groupId>
- <artifactId>oss-parent</artifactId>
- <version>7</version>
+ <groupId>org.apache</groupId>
+ <artifactId>apache</artifactId>
+ <version>31</version>
</parent>
- <groupId>com.alibaba</groupId>
+ <groupId>org.apache.dubbo</groupId>
<artifactId>hessian-lite</artifactId>
<packaging>jar</packaging>
- <version>3.2.13</version>
+ <version>4.0.0-SNAPSHOT</version>
<name>Hessian Lite(Dubbo embed version)</name>
<properties>
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/HessianUnshared.java
similarity index 78%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/HessianUnshared.java
index 72a9822..88377c8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/HessianUnshared.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,20 +46,22 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
+package com.alibaba.com.caucho.hessian;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Marks the class and all children as unshared.
+ * A reference item will be created, but will not be stored in a
+ * mapped or checked for duplicated.
+ * <p>
+ * Used for efficiency to avoid the cost of the map lookup.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
- }
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HessianUnshared {
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java
index 042d14e..eabdbf9 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializer.java
@@ -53,13 +53,17 @@
/**
* Deserializing an object.
*/
-abstract public class AbstractDeserializer implements Deserializer {
- @Override
- public Class getType() {
+public class AbstractDeserializer implements Deserializer {
+ public static final NullDeserializer NULL = new NullDeserializer();
+
+ public Class<?> getType() {
return Object.class;
}
- @Override
+ public boolean isReadResolve() {
+ return false;
+ }
+
public Object readObject(AbstractHessianInput in)
throws IOException {
Object obj = in.readObject();
@@ -72,35 +76,16 @@
throw error(className + ": unexpected null value");
}
- @Override
public Object readList(AbstractHessianInput in, int length)
throws IOException {
throw new UnsupportedOperationException(String.valueOf(this));
}
- @Override
- public Object readList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
- if (expectType == null) {
- return readList(in, length);
- }
- throw new UnsupportedOperationException(String.valueOf(this));
- }
-
- @Override
public Object readLengthList(AbstractHessianInput in, int length)
throws IOException {
throw new UnsupportedOperationException(String.valueOf(this));
}
- @Override
- public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
- if (expectType == null) {
- return readLengthList(in, length);
- }
- throw new UnsupportedOperationException(String.valueOf(this));
- }
-
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
Object obj = in.readObject();
@@ -113,18 +98,43 @@
throw error(className + ": unexpected null value");
}
- @Override
- public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType) throws IOException {
- if (expectKeyType == null && expectValueType == null) {
- return readMap(in);
- }
- throw new UnsupportedOperationException(String.valueOf(this));
+ /**
+ * Creates the field array for a class. The default
+ * implementation returns a String[] array.
+ *
+ * @param len number of items in the array
+ * @return the new empty array
+ */
+ public Object[] createFields(int len) {
+ return new String[len];
+ }
+
+ /**
+ * Creates a field value class. The default
+ * implementation returns the String.
+ *
+ * @param len number of items in the array
+ * @return the new empty array
+ */
+ public Object createField(String name) {
+ return name;
}
@Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object readObject(AbstractHessianInput in,
+ String[] fieldNames)
throws IOException {
- throw new UnsupportedOperationException(String.valueOf(this));
+ return readObject(in, (Object[]) fieldNames);
+ }
+
+ /**
+ * Reads an object instance from the input stream
+ */
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
+ throws IOException {
+ throw new UnsupportedOperationException(toString());
}
protected HessianProtocolException error(String msg) {
@@ -138,13 +148,10 @@
return "0x" + Integer.toHexString(ch & 0xff);
}
- protected SerializerFactory findSerializerFactory(AbstractHessianInput in) {
- SerializerFactory serializerFactory = null;
- if (in instanceof Hessian2Input) {
- serializerFactory = ((Hessian2Input) in).findSerializerFactory();
- } else if (in instanceof HessianInput) {
- serializerFactory = ((HessianInput) in).getSerializerFactory();
- }
- return serializerFactory == null ? new SerializerFactory() : serializerFactory;
+ /**
+ * The NullDeserializer exists as a marker for the factory classes so
+ * they save a null result.
+ */
+ static final class NullDeserializer extends AbstractDeserializer {
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializerWrapper.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializerWrapper.java
new file mode 100644
index 0000000..f38977e
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractDeserializerWrapper.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializing an object.
+ */
+abstract public class AbstractDeserializerWrapper implements Deserializer {
+ abstract protected Deserializer getDelegate();
+
+ @Override
+ public Class<?> getType() {
+ return getDelegate().getType();
+ }
+
+ @Override
+ public boolean isReadResolve() {
+ return getDelegate().isReadResolve();
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in)
+ throws IOException {
+ return getDelegate().readObject(in);
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException {
+ return getDelegate().readList(in, length);
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException {
+ return getDelegate().readLengthList(in, length);
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ return getDelegate().readMap(in);
+ }
+
+ /**
+ * Creates the field array for a class. The default
+ * implementation returns a String[] array.
+ *
+ * @param len number of items in the array
+ * @return the new empty array
+ */
+ @Override
+ public Object[] createFields(int len) {
+ return getDelegate().createFields(len);
+ }
+
+ /**
+ * Creates a field value class. The default
+ * implementation returns the String.
+ *
+ * @param len number of items in the array
+ * @return the new empty array
+ */
+ @Override
+ public Object createField(String name) {
+ return getDelegate().createField(name);
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ String[] fieldNames)
+ throws IOException {
+ return getDelegate().readObject(in, fieldNames);
+ }
+
+ /**
+ * Reads an object instance from the input stream
+ */
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
+ throws IOException {
+ return getDelegate().readObject(in, fields);
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
index db0e574..ebb1539 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianInput.java
@@ -50,13 +50,13 @@
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.Reader;
-import java.util.List;
/**
* Abstract base class for Hessian requests. Hessian users should only
* need to use the methods in this class.
- * <p>
+ *
* <pre>
* AbstractHessianInput in = ...; // get input
* String value;
@@ -68,6 +68,7 @@
*/
abstract public class AbstractHessianInput {
private HessianRemoteResolver resolver;
+ private byte[] _buffer;
/**
* Initialize the Hessian stream with the underlying input stream.
@@ -100,11 +101,9 @@
public void setSerializerFactory(SerializerFactory ser) {
}
- public abstract boolean checkAndReadNull();
-
/**
* Reads the call
- * <p>
+ *
* <pre>
* c major minor
* </pre>
@@ -121,7 +120,7 @@
/**
* Reads a header, returning null if there are no headers.
- * <p>
+ *
* <pre>
* H b16 b8 value
* </pre>
@@ -131,9 +130,9 @@
/**
* Starts reading the call
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* m b16 b8 method
* </pre>
@@ -153,9 +152,9 @@
/**
* Starts reading the call, including the headers.
- * <p>
+ *
* <p>The call expects the following protocol data
- * <p>
+ *
* <pre>
* c major minor
* m b16 b8 method
@@ -166,9 +165,9 @@
/**
* Completes reading the call
- * <p>
+ *
* <p>The call expects the following protocol data
- * <p>
+ *
* <pre>
* Z
* </pre>
@@ -185,9 +184,9 @@
/**
* Starts reading the reply
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* r
* v
@@ -197,10 +196,18 @@
throws Throwable;
/**
+ * Starts reading the body of the reply, i.e. after the 'r' has been
+ * parsed.
+ */
+ public void startReplyBody()
+ throws Throwable {
+ }
+
+ /**
* Completes reading the call
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* z
* </pre>
@@ -210,7 +217,7 @@
/**
* Reads a boolean
- * <p>
+ *
* <pre>
* T
* F
@@ -221,7 +228,7 @@
/**
* Reads a null
- * <p>
+ *
* <pre>
* N
* </pre>
@@ -231,7 +238,7 @@
/**
* Reads an integer
- * <p>
+ *
* <pre>
* I b32 b24 b16 b8
* </pre>
@@ -241,7 +248,7 @@
/**
* Reads a long
- * <p>
+ *
* <pre>
* L b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
@@ -251,7 +258,7 @@
/**
* Reads a double.
- * <p>
+ *
* <pre>
* D b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
@@ -261,7 +268,7 @@
/**
* Reads a date.
- * <p>
+ *
* <pre>
* T b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
@@ -271,7 +278,7 @@
/**
* Reads a string encoded in UTF-8
- * <p>
+ *
* <pre>
* s b16 b8 non-final string chunk
* S b16 b8 final string chunk
@@ -282,7 +289,7 @@
/**
* Reads an XML node encoded in UTF-8
- * <p>
+ *
* <pre>
* x b16 b8 non-final xml chunk
* X b16 b8 final xml chunk
@@ -297,7 +304,7 @@
* Starts reading a string. All the characters must be read before
* calling the next method. The actual characters will be read with
* the reader's read() or read(char [], int, int).
- * <p>
+ *
* <pre>
* s b16 b8 non-final string chunk
* S b16 b8 final string chunk
@@ -309,7 +316,7 @@
/**
* Starts reading a byte array using an input stream. All the bytes
* must be read before calling the following method.
- * <p>
+ *
* <pre>
* b b16 b8 non-final binary chunk
* B b16 b8 final binary chunk
@@ -319,8 +326,40 @@
throws IOException;
/**
+ * Reads data to an output stream.
+ *
+ * <pre>
+ * b b16 b8 non-final binary chunk
+ * B b16 b8 final binary chunk
+ * </pre>
+ */
+ public boolean readToOutputStream(OutputStream os)
+ throws IOException {
+ InputStream is = readInputStream();
+
+ if (is == null)
+ return false;
+
+ if (_buffer == null)
+ _buffer = new byte[256];
+
+ try {
+ int len;
+
+ while ((len = is.read(_buffer, 0, _buffer.length)) > 0) {
+ os.write(_buffer, 0, len);
+ }
+
+ return true;
+ } finally {
+ is.close();
+ }
+ }
+
+
+ /**
* Reads a byte array.
- * <p>
+ *
* <pre>
* b b16 b8 non-final binary chunk
* B b16 b8 final binary chunk
@@ -339,37 +378,14 @@
/**
* Reads an arbitrary object from the input stream.
- *
- * @param expectedClass the expected class if the protocol doesn't supply it.
- * @param expectedTypes the runtime type hints, eg: expectedClass equals Map, expectedTypes can
- * equals String.class, Short.class
- */
- public Object readObject(Class expectedClass, Class<?>... expectedTypes)
- throws IOException {
- throw new UnsupportedOperationException(String.valueOf(this));
- }
-
- /**
- * Reads an arbitrary object from the input stream.
*/
abstract public Object readObject()
throws IOException;
/**
- * Reads an arbitrary object from the input stream.
- *
- * @param expectedTypes the runtime type hints, eg: expectedTypes can
- * equals String.class, Short.class for HashMap
- */
- public Object readObject(List<Class<?>> expectedTypes)
- throws IOException {
- throw new UnsupportedOperationException(String.valueOf(this));
- }
-
- /**
* Reads a remote object reference to the stream. The type is the
* type of the remote interface.
- * <p>
+ *
* <code><pre>
* 'r' 't' b16 b8 type url
* </pre></code>
@@ -379,7 +395,7 @@
/**
* Reads a reference
- * <p>
+ *
* <pre>
* R b32 b24 b16 b8
* </pre>
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java
index 6021408..515b009 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianOutput.java
@@ -49,11 +49,12 @@
package com.alibaba.com.caucho.hessian.io;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
/**
* Abstract output stream for Hessian requests.
- * <p>
+ *
* <pre>
* OutputStream os = ...; // from http connection
* AbstractOutput out = new HessianSerializerOutput(os);
@@ -67,11 +68,20 @@
abstract public class AbstractHessianOutput {
// serializer factory
protected SerializerFactory _serializerFactory;
+ // serializer factory
+ private SerializerFactory _defaultSerializerFactory;
+ private byte[] _byteBuffer;
/**
* Gets the serializer factory.
*/
public SerializerFactory getSerializerFactory() {
+ // the default serializer factory cannot be modified by external
+ // callers
+ if (_serializerFactory == _defaultSerializerFactory) {
+ _serializerFactory = new SerializerFactory();
+ }
+
return _serializerFactory;
}
@@ -85,11 +95,14 @@
/**
* Gets the serializer factory.
*/
- public final SerializerFactory findSerializerFactory() {
+ protected final SerializerFactory findSerializerFactory() {
SerializerFactory factory = _serializerFactory;
- if (factory == null)
- _serializerFactory = factory = new SerializerFactory();
+ if (factory == null) {
+ factory = SerializerFactory.createDefault();
+ _defaultSerializerFactory = factory;
+ _serializerFactory = factory;
+ }
return factory;
}
@@ -100,6 +113,10 @@
public void init(OutputStream os) {
}
+ public boolean setUnshared(boolean isUnshared) {
+ throw new UnsupportedOperationException(getClass().getSimpleName());
+ }
+
/**
* Writes a complete method call.
*/
@@ -117,7 +134,7 @@
/**
* Starts the method call:
- * <p>
+ *
* <code><pre>
* C
* </pre></code>
@@ -129,7 +146,7 @@
/**
* Starts the method call:
- * <p>
+ *
* <code><pre>
* C string int
* </pre></code>
@@ -151,7 +168,7 @@
/**
* Writes the method tag.
- * <p>
+ *
* <code><pre>
* string
* </pre></code>
@@ -163,7 +180,7 @@
/**
* Completes the method call:
- * <p>
+ *
* <code><pre>
* </pre></code>
*/
@@ -173,7 +190,7 @@
/**
* Writes a boolean value to the stream. The boolean will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* T
* F
@@ -187,7 +204,7 @@
/**
* Writes an integer value to the stream. The integer will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* I b32 b24 b16 b8
* </pre></code>
@@ -200,7 +217,7 @@
/**
* Writes a long value to the stream. The long will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* L b64 b56 b48 b40 b32 b24 b16 b8
* </pre></code>
@@ -213,7 +230,7 @@
/**
* Writes a double value to the stream. The double will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* D b64 b56 b48 b40 b32 b24 b16 b8
* </pre></code>
@@ -225,7 +242,7 @@
/**
* Writes a date to the stream.
- * <p>
+ *
* <code><pre>
* T b64 b56 b48 b40 b32 b24 b16 b8
* </pre></code>
@@ -238,7 +255,7 @@
/**
* Writes a null value to the stream.
* The null will be written with the following syntax
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
@@ -251,13 +268,13 @@
/**
* Writes a string value to the stream using UTF-8 encoding.
* The string will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* S b16 b8 string-value
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
@@ -270,13 +287,13 @@
/**
* Writes a string value to the stream using UTF-8 encoding.
* The string will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* S b16 b8 string-value
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
@@ -289,13 +306,13 @@
/**
* Writes a byte array to the stream.
* The array will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* B b16 b18 bytes
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
@@ -308,13 +325,13 @@
/**
* Writes a byte array to the stream.
* The array will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* B b16 b18 bytes
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
@@ -332,7 +349,7 @@
/**
* Writes a byte buffer to the stream.
- * <p>
+ *
* <code><pre>
* b b16 b18 bytes
* </pre></code>
@@ -346,7 +363,7 @@
/**
* Writes the last chunk of a byte buffer to the stream.
- * <p>
+ *
* <code><pre>
* b b16 b18 bytes
* </pre></code>
@@ -359,8 +376,39 @@
throws IOException;
/**
+ * Writes a full output stream.
+ */
+ public void writeByteStream(InputStream is)
+ throws IOException {
+ writeByteBufferStart();
+
+ if (_byteBuffer == null)
+ _byteBuffer = new byte[1024];
+
+ byte[] buffer = _byteBuffer;
+
+ int len;
+ while ((len = is.read(buffer, 0, buffer.length)) > 0) {
+ if (len < buffer.length) {
+ int len2 = is.read(buffer, len, buffer.length - len);
+
+ if (len2 < 0) {
+ writeByteBufferEnd(buffer, 0, len);
+ return;
+ }
+
+ len += len2;
+ }
+
+ writeByteBufferPart(buffer, 0, len);
+ }
+
+ writeByteBufferEnd(buffer, 0, 0);
+ }
+
+ /**
* Writes a reference.
- * <p>
+ *
* <code><pre>
* Q int
* </pre></code>
@@ -373,8 +421,10 @@
/**
* Removes a reference.
*/
- abstract public boolean removeRef(Object obj)
- throws IOException;
+ public boolean removeRef(Object obj)
+ throws IOException {
+ return false;
+ }
/**
* Replaces a reference from one object to another.
@@ -386,7 +436,7 @@
* Adds an object to the reference list. If the object already exists,
* writes the reference, otherwise, the caller is responsible for
* the serialization.
- * <p>
+ *
* <code><pre>
* R b32 b24 b16 b8
* </pre></code>
@@ -398,6 +448,12 @@
throws IOException;
/**
+ * @param obj
+ * @return
+ */
+ abstract public int getRef(Object obj);
+
+ /**
* Resets the references for streaming.
*/
public void resetReferences() {
@@ -413,7 +469,7 @@
* Writes the list header to the stream. List writers will call
* <code>writeListBegin</code> followed by the list contents and then
* call <code>writeListEnd</code>.
- * <p>
+ *
* <code><pre>
* V
* x13 java.util.ArrayList # type
@@ -437,7 +493,7 @@
* Writes the map header to the stream. Map writers will call
* <code>writeMapBegin</code> followed by the map contents and then
* call <code>writeMapEnd</code>.
- * <p>
+ *
* <code><pre>
* M type (<key> <value>)* Z
* </pre></code>
@@ -456,7 +512,7 @@
* Map for Hessian 1.0. Object writers will call
* <code>writeObjectBegin</code> followed by the map contents and then
* call <code>writeObjectEnd</code>.
- * <p>
+ *
* <code><pre>
* C type int <key>*
* C int <value>*
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java
index aad1b38..8cf8717 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractListDeserializer.java
@@ -54,7 +54,6 @@
* Deserializing a JDK 1.2 Collection.
*/
public class AbstractListDeserializer extends AbstractDeserializer {
- @Override
public Object readObject(AbstractHessianInput in)
throws IOException {
Object obj = in.readObject();
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java
index d18faf1..df265b3 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractMapDeserializer.java
@@ -56,12 +56,10 @@
*/
public class AbstractMapDeserializer extends AbstractDeserializer {
- @Override
public Class getType() {
return HashMap.class;
}
- @Override
public Object readObject(AbstractHessianInput in)
throws IOException {
Object obj = in.readObject();
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java
index 088cf25..199d17a 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializer.java
@@ -48,6 +48,8 @@
package com.alibaba.com.caucho.hessian.io;
+import com.alibaba.com.caucho.hessian.HessianException;
+
import java.io.IOException;
import java.util.logging.Logger;
@@ -55,10 +57,88 @@
* Serializing an object.
*/
abstract public class AbstractSerializer implements Serializer {
+ public static final NullSerializer NULL = new NullSerializer();
+
protected static final Logger log
= Logger.getLogger(AbstractSerializer.class.getName());
@Override
- abstract public void writeObject(Object obj, AbstractHessianOutput out)
- throws IOException;
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ try {
+ Object replace = writeReplace(obj);
+
+ if (replace != null) {
+ // out.removeRef(obj);
+
+ out.writeObject(replace);
+
+ out.replaceRef(replace, obj);
+
+ return;
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ // log.log(Level.FINE, e.toString(), e);
+ throw new HessianException(e);
+ }
+
+ Class<?> cl = getClass(obj);
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ writeObject10(obj, out);
+ } else {
+ if (ref == -1) {
+ writeDefinition20(cl, out);
+
+ out.writeObjectBegin(cl.getName());
+ }
+
+ writeInstance(obj, out);
+ }
+ }
+
+ protected Object writeReplace(Object obj) {
+ return null;
+ }
+
+ protected Class<?> getClass(Object obj) {
+ return obj.getClass();
+ }
+
+ protected void writeObject10(Object obj,
+ AbstractHessianOutput out)
+ throws IOException {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ protected void writeDefinition20(Class<?> cl,
+ AbstractHessianOutput out)
+ throws IOException {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ protected void writeInstance(Object obj,
+ AbstractHessianOutput out)
+ throws IOException {
+ throw new UnsupportedOperationException(getClass().getName());
+ }
+
+ /**
+ * The NullSerializer exists as a marker for the factory classes so
+ * they save a null result.
+ */
+ static final class NullSerializer extends AbstractSerializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ throw new IllegalStateException(getClass().getName());
+ }
+ }
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializerWrapper.java
similarity index 82%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializerWrapper.java
index 72a9822..078664c 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractSerializerWrapper.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -49,17 +49,20 @@
package com.alibaba.com.caucho.hessian.io;
import java.io.IOException;
+import java.util.logging.Logger;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+abstract public class AbstractSerializerWrapper implements Serializer {
+ protected static final Logger log
+ = Logger.getLogger(AbstractSerializerWrapper.class.getName());
+
+ abstract protected Serializer getDelegate();
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ getDelegate().writeObject(obj, out);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStreamDeserializer.java
similarity index 67%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStreamDeserializer.java
index 72a9822..eb7deac 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStreamDeserializer.java
@@ -51,15 +51,52 @@
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing a byte stream
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+abstract public class AbstractStreamDeserializer extends AbstractDeserializer {
+ abstract public Class<?> getType();
+
/**
- * Looks up a proxy object.
+ * Reads the Hessian 1.0 style map.
*/
@Override
- public Object lookup(String type, String url)
+ public Object readMap(AbstractHessianInput in)
throws IOException {
- return new HessianRemote(type, url);
+ Object value = null;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ value = readStreamValue(in);
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ return value;
}
+
+ @Override
+ public Object readObject(AbstractHessianInput in, Object[] fields)
+ throws IOException {
+ String[] fieldNames = (String[]) fields;
+
+ Object value = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i])) {
+ value = readStreamValue(in);
+ in.addRef(value);
+ } else {
+ in.readObject();
+ }
+ }
+
+ return value;
+ }
+
+ abstract protected Object readStreamValue(AbstractHessianInput in)
+ throws IOException;
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStreamSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStreamSerializer.java
new file mode 100644
index 0000000..794d537
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStreamSerializer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.logging.Level;
+
+/**
+ * Serializing an object containing a byte stream.
+ */
+abstract public class AbstractStreamSerializer extends AbstractSerializer {
+ /**
+ * Writes the object to the output stream.
+ */
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ int ref = out.writeObjectBegin(getClassName(obj));
+
+ if (ref < -1) {
+ out.writeString("value");
+
+ InputStream is = null;
+
+ try {
+ is = getInputStream(obj);
+ } catch (Exception e) {
+ log.log(Level.WARNING, e.toString(), e);
+ }
+
+ if (is != null) {
+ try {
+ out.writeByteStream(is);
+ } finally {
+ is.close();
+ }
+ } else {
+ out.writeNull();
+ }
+
+ out.writeMapEnd();
+ } else {
+ if (ref == -1) {
+ out.writeClassFieldLength(1);
+ out.writeString("value");
+
+ out.writeObjectBegin(getClassName(obj));
+ }
+
+ InputStream is = null;
+
+ try {
+ is = getInputStream(obj);
+ } catch (Exception e) {
+ log.log(Level.WARNING, e.toString(), e);
+ }
+
+ try {
+ if (is != null)
+ out.writeByteStream(is);
+ else
+ out.writeNull();
+ } finally {
+ if (is != null)
+ is.close();
+ }
+ }
+ }
+
+ protected String getClassName(Object obj) {
+ return obj.getClass().getName();
+ }
+
+ abstract protected InputStream getInputStream(Object obj)
+ throws IOException;
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStringValueDeserializer.java
similarity index 67%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStringValueDeserializer.java
index 72a9822..9824158 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractStringValueDeserializer.java
@@ -51,15 +51,54 @@
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializes a string-valued object like BigDecimal.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+abstract public class AbstractStringValueDeserializer
+ extends AbstractDeserializer {
+ abstract protected Object create(String value)
+ throws IOException;
+
@Override
- public Object lookup(String type, String url)
+ public Object readMap(AbstractHessianInput in)
throws IOException {
- return new HessianRemote(type, url);
+ String value = null;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ value = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object object = create(value);
+
+ in.addRef(object);
+
+ return object;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, Object[] fields)
+ throws IOException {
+ String[] fieldNames = (String[]) fields;
+
+ String value = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i]))
+ value = in.readString();
+ else
+ in.readObject();
+ }
+
+ Object object = create(value);
+
+ in.addRef(object);
+
+ return object;
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationDeserializer.java
new file mode 100644
index 0000000..7b04ccf
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationDeserializer.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import com.alibaba.com.caucho.hessian.HessianException;
+
+import java.io.IOException;
+import java.lang.reflect.Proxy;
+import java.util.HashMap;
+import java.util.logging.Logger;
+
+/**
+ * Deserializing a java annotation for known object types.
+ */
+public class AnnotationDeserializer extends AbstractMapDeserializer {
+ private static final Logger log
+ = Logger.getLogger(AnnotationDeserializer.class.getName());
+
+ private Class _annType;
+
+ public AnnotationDeserializer(Class annType) {
+ _annType = annType;
+ }
+
+ public Class getType() {
+ return _annType;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ try {
+ int ref = in.addRef(null);
+
+ HashMap<String, Object> valueMap = new HashMap<String, Object>(8);
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+ Object value = in.readObject();
+
+ valueMap.put(key, value);
+ }
+
+ in.readMapEnd();
+
+ return Proxy.newProxyInstance(_annType.getClassLoader(),
+ new Class[]{_annType},
+ new AnnotationInvocationHandler(_annType, valueMap));
+
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
+ throws IOException {
+ String[] fieldNames = (String[]) fields;
+
+ try {
+ in.addRef(null);
+
+ HashMap<String, Object> valueMap = new HashMap<String, Object>(8);
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String name = fieldNames[i];
+
+ valueMap.put(name, in.readObject());
+ }
+
+ return Proxy.newProxyInstance(_annType.getClassLoader(),
+ new Class[]{_annType},
+ new AnnotationInvocationHandler(_annType, valueMap));
+
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new HessianException(_annType.getName() + ":" + e, e);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationInvocationHandler.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationInvocationHandler.java
new file mode 100644
index 0000000..34fef0f
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationInvocationHandler.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Proxy for a java annotation for known object types.
+ */
+public class AnnotationInvocationHandler implements InvocationHandler {
+ private Class _annType;
+ private HashMap<String, Object> _valueMap;
+
+ public AnnotationInvocationHandler(Class annType,
+ HashMap<String, Object> valueMap) {
+ _annType = annType;
+ _valueMap = valueMap;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ String name = method.getName();
+
+ boolean zeroArgs = args == null || args.length == 0;
+
+ if (name.equals("annotationType") && zeroArgs)
+ return _annType;
+ else if (name.equals("toString") && zeroArgs)
+ return toString();
+ else if (name.equals("hashCode") && zeroArgs)
+ return doHashCode();
+ else if (name.equals("equals") && !zeroArgs && args.length == 1)
+ return doEquals(args[0]);
+ else if (!zeroArgs)
+ return null;
+
+
+ return _valueMap.get(method.getName());
+ }
+
+ public int doHashCode() {
+ return 13;
+ }
+
+ public boolean doEquals(Object value) {
+ if (!(value instanceof Annotation))
+ return false;
+
+ Annotation ann = (Annotation) value;
+
+ if (!_annType.equals(ann.annotationType()))
+ return false;
+
+ return true;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("@");
+ sb.append(_annType.getName());
+ sb.append("[");
+
+ boolean isFirst = true;
+ for (Map.Entry entry : _valueMap.entrySet()) {
+ if (!isFirst)
+ sb.append(", ");
+ isFirst = false;
+
+ sb.append(entry.getKey());
+ sb.append("=");
+
+ if (entry.getValue() instanceof String)
+ sb.append('"').append(entry.getValue()).append('"');
+ else
+ sb.append(entry.getValue());
+ }
+ sb.append("]");
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationSerializer.java
new file mode 100644
index 0000000..10cf3ef
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/AnnotationSerializer.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import com.alibaba.com.caucho.hessian.HessianException;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing a Java annotation
+ */
+public class AnnotationSerializer extends AbstractSerializer {
+ private static final Logger log
+ = Logger.getLogger(AnnotationSerializer.class.getName());
+
+ private static Object[] NULL_ARGS = new Object[0];
+
+ private Class _annType;
+ private Method[] _methods;
+ private MethodSerializer[] _methodSerializers;
+
+ public AnnotationSerializer(Class annType) {
+ if (!Annotation.class.isAssignableFrom(annType)) {
+ throw new IllegalStateException(annType.getName() + " is invalid because it is not a java.lang.annotation.Annotation");
+ }
+ }
+
+ private static MethodSerializer getMethodSerializer(Class type) {
+ if (int.class.equals(type)
+ || byte.class.equals(type)
+ || short.class.equals(type)
+ || int.class.equals(type)) {
+ return IntMethodSerializer.SER;
+ } else if (long.class.equals(type)) {
+ return LongMethodSerializer.SER;
+ } else if (double.class.equals(type) ||
+ float.class.equals(type)) {
+ return DoubleMethodSerializer.SER;
+ } else if (boolean.class.equals(type)) {
+ return BooleanMethodSerializer.SER;
+ } else if (String.class.equals(type)) {
+ return StringMethodSerializer.SER;
+ } else if (java.util.Date.class.equals(type)
+ || java.sql.Date.class.equals(type)
+ || java.sql.Timestamp.class.equals(type)
+ || java.sql.Time.class.equals(type)) {
+ return DateMethodSerializer.SER;
+ } else
+ return MethodSerializer.SER;
+ }
+
+ static HessianException error(Method method, Throwable cause) {
+ String msg = (method.getDeclaringClass().getSimpleName()
+ + "." + method.getName() + "(): " + cause);
+
+ throw new HessianMethodSerializationException(msg, cause);
+ }
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ init(((Annotation) obj).annotationType());
+
+ int ref = out.writeObjectBegin(_annType.getName());
+
+ if (ref < -1) {
+ writeObject10(obj, out);
+ } else {
+ if (ref == -1) {
+ writeDefinition20(out);
+ out.writeObjectBegin(_annType.getName());
+ }
+
+ writeInstance(obj, out);
+ }
+ }
+
+ protected void writeObject10(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ for (int i = 0; i < _methods.length; i++) {
+ Method method = _methods[i];
+
+ out.writeString(method.getName());
+
+ _methodSerializers[i].serialize(out, obj, method);
+ }
+
+ out.writeMapEnd();
+ }
+
+ private void writeDefinition20(AbstractHessianOutput out)
+ throws IOException {
+ out.writeClassFieldLength(_methods.length);
+
+ for (int i = 0; i < _methods.length; i++) {
+ Method method = _methods[i];
+
+ out.writeString(method.getName());
+ }
+ }
+
+ public void writeInstance(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ for (int i = 0; i < _methods.length; i++) {
+ Method method = _methods[i];
+
+ _methodSerializers[i].serialize(out, obj, method);
+ }
+ }
+
+ private void init(Class cl) {
+ synchronized (this) {
+ if (_annType != null)
+ return;
+
+ _annType = cl;
+
+ ArrayList methods = new ArrayList();
+
+ for (Method method : _annType.getDeclaredMethods()) {
+ if (method.getName().equals("hashCode")
+ || method.getName().equals("toString")
+ || method.getName().equals("annotationType")) {
+ continue;
+ }
+
+ if (method.getParameterTypes().length != 0)
+ continue;
+
+ methods.add(method);
+
+ method.setAccessible(true);
+ }
+
+ if (_annType == null)
+ throw new IllegalStateException(cl.getName() + " is invalid because it does not have a valid annotationType()");
+
+ _methods = new Method[methods.size()];
+ methods.toArray(_methods);
+
+ _methodSerializers = new MethodSerializer[_methods.length];
+
+ for (int i = 0; i < _methods.length; i++) {
+ _methodSerializers[i] = getMethodSerializer(_methods[i].getReturnType());
+ }
+ }
+ }
+
+ private Class getAnnotationType(Class cl) {
+ if (cl == null)
+ return null;
+
+ if (Annotation.class.equals(cl.getSuperclass()))
+ return cl;
+
+ Class ifaces[] = cl.getInterfaces();
+
+ if (ifaces != null) {
+ for (Class iface : ifaces) {
+ if (iface.equals(Annotation.class))
+ return cl;
+
+ Class annType = getAnnotationType(iface);
+
+ if (annType != null)
+ return annType;
+ }
+ }
+
+ return getAnnotationType(cl.getSuperclass());
+ }
+
+ static class MethodSerializer {
+ static final MethodSerializer SER = new MethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ Object value = null;
+
+ try {
+ value = method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ try {
+ out.writeObject(value);
+ } catch (Exception e) {
+ throw error(method, e);
+ }
+ }
+ }
+
+ static class BooleanMethodSerializer extends MethodSerializer {
+ static final MethodSerializer SER = new BooleanMethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ boolean value = false;
+
+ try {
+ value = (Boolean) method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeBoolean(value);
+ }
+ }
+
+ static class IntMethodSerializer extends MethodSerializer {
+ static final MethodSerializer SER = new IntMethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = (Integer) method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeInt(value);
+ }
+ }
+
+ static class LongMethodSerializer extends MethodSerializer {
+ static final MethodSerializer SER = new LongMethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ long value = 0;
+
+ try {
+ value = (Long) method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeLong(value);
+ }
+ }
+
+ static class DoubleMethodSerializer extends MethodSerializer {
+ static final MethodSerializer SER = new DoubleMethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = (Double) method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeDouble(value);
+ }
+ }
+
+ static class StringMethodSerializer extends MethodSerializer {
+ static final MethodSerializer SER = new StringMethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ String value = null;
+
+ try {
+ value = (String) method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeString(value);
+ }
+ }
+
+ static class DateMethodSerializer extends MethodSerializer {
+ static final MethodSerializer SER = new DateMethodSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Method method)
+ throws IOException {
+ java.util.Date value = null;
+
+ try {
+ value = (java.util.Date) method.invoke(obj);
+ } catch (InvocationTargetException e) {
+ throw error(method, e.getCause());
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ if (value == null)
+ out.writeNull();
+ else
+ out.writeUTCDate(value.getTime());
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java
index e575411..8c7c715 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ArrayDeserializer.java
@@ -73,7 +73,6 @@
_type = Object[].class;
}
- @Override
public Class getType() {
return _type;
}
@@ -81,7 +80,6 @@
/**
* Reads the array.
*/
- @Override
public Object readList(AbstractHessianInput in, int length)
throws IOException {
if (length >= 0) {
@@ -126,7 +124,6 @@
/**
* Reads the array.
*/
- @Override
public Object readLengthList(AbstractHessianInput in, int length)
throws IOException {
Object[] data = createArray(length);
@@ -151,7 +148,6 @@
return new Object[length];
}
- @Override
public String toString() {
return "ArrayDeserializer[" + _componentType + "]";
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java
index d6cfcc5..31d7ca5 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ArraySerializer.java
@@ -54,7 +54,6 @@
* Serializing a Java array.
*/
public class ArraySerializer extends AbstractSerializer {
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
if (out.addRef(obj))
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
index 81146ca..52589d6 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/BasicDeserializer.java
@@ -88,7 +88,6 @@
_code = code;
}
- @Override
public Class getType() {
switch (_code) {
case NULL:
@@ -148,9 +147,6 @@
@Override
public Object readObject(AbstractHessianInput in)
throws IOException {
- if (in.checkAndReadNull()) {
- return null;
- }
switch (_code) {
case NULL:
// hessian/3490
@@ -515,7 +511,6 @@
}
}
- @Override
public Object readLengthList(AbstractHessianInput in, int length)
throws IOException {
switch (_code) {
@@ -608,8 +603,7 @@
}
}
- public String toString()
- {
+ public String toString() {
return getClass().getSimpleName() + "[" + _code + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java
index 4b9f359..207c9d0 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/BasicSerializer.java
@@ -54,7 +54,8 @@
/**
* Serializing an object for known object types.
*/
-public class BasicSerializer extends AbstractSerializer {
+public class BasicSerializer extends AbstractSerializer
+ implements ObjectSerializer {
public static final int NULL = 0;
public static final int BOOLEAN = NULL + 1;
public static final int BYTE = BOOLEAN + 1;
@@ -66,7 +67,8 @@
public static final int CHARACTER = DOUBLE + 1;
public static final int CHARACTER_OBJECT = CHARACTER + 1;
public static final int STRING = CHARACTER_OBJECT + 1;
- public static final int DATE = STRING + 1;
+ public static final int STRING_BUILDER = STRING + 1;
+ public static final int DATE = STRING_BUILDER + 1;
public static final int NUMBER = DATE + 1;
public static final int OBJECT = NUMBER + 1;
@@ -81,16 +83,37 @@
public static final int STRING_ARRAY = CHARACTER_ARRAY + 1;
public static final int OBJECT_ARRAY = STRING_ARRAY + 1;
- private int code;
+ public static final int BYTE_HANDLE = OBJECT_ARRAY + 1;
+ public static final int SHORT_HANDLE = BYTE_HANDLE + 1;
+ public static final int FLOAT_HANDLE = SHORT_HANDLE + 1;
+ private static final BasicSerializer FLOAT_HANDLE_SERIALIZER
+ = new BasicSerializer(FLOAT_HANDLE);
+ private static final BasicSerializer SHORT_HANDLE_SERIALIZER
+ = new BasicSerializer(SHORT_HANDLE);
+ private static final BasicSerializer BYTE_HANDLE_SERIALIZER
+ = new BasicSerializer(BYTE_HANDLE);
+ private int _code;
public BasicSerializer(int code) {
- this.code = code;
+ _code = code;
}
- @Override
+ public Serializer getObjectSerializer() {
+ switch (_code) {
+ case BYTE:
+ return BYTE_HANDLE_SERIALIZER;
+ case SHORT:
+ return SHORT_HANDLE_SERIALIZER;
+ case FLOAT:
+ return FLOAT_HANDLE_SERIALIZER;
+ default:
+ return this;
+ }
+ }
+
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- switch (code) {
+ switch (_code) {
case BOOLEAN:
out.writeBoolean(((Boolean) obj).booleanValue());
break;
@@ -121,6 +144,10 @@
out.writeString((String) obj);
break;
+ case STRING_BUILDER:
+ out.writeString(((StringBuilder) obj).toString());
+ break;
+
case DATE:
out.writeUTCDate(((Date) obj).getTime());
break;
@@ -269,8 +296,24 @@
out.writeNull();
break;
+ case OBJECT:
+ ObjectHandleSerializer.SER.writeObject(obj, out);
+ break;
+
+ case BYTE_HANDLE:
+ out.writeObject(new ByteHandle((Byte) obj));
+ break;
+
+ case SHORT_HANDLE:
+ out.writeObject(new ShortHandle((Short) obj));
+ break;
+
+ case FLOAT_HANDLE:
+ out.writeObject(new FloatHandle((Float) obj));
+ break;
+
default:
- throw new RuntimeException(code + " " + String.valueOf(obj.getClass()));
+ throw new RuntimeException(_code + " unknown code for " + obj.getClass());
}
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java
index a0f16c8..5bc4db2 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/BeanDeserializer.java
@@ -53,6 +53,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
+import java.util.Locale;
/**
* Serializing an object for known object types.
@@ -116,12 +117,10 @@
throw new UnsupportedOperationException();
}
- @Override
public Class getType() {
return _type;
}
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
try {
@@ -248,9 +247,9 @@
}
if (j == 1)
- name = name.substring(0, j).toLowerCase() + name.substring(j);
+ name = name.substring(0, j).toLowerCase(Locale.ENGLISH) + name.substring(j);
else if (j > 1)
- name = name.substring(0, j - 1).toLowerCase() + name.substring(j - 1);
+ name = name.substring(0, j - 1).toLowerCase(Locale.ENGLISH) + name.substring(j - 1);
methodMap.put(name, method);
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/BigDecimalDeserializer.java
similarity index 87%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/BigDecimalDeserializer.java
index be505fb..23ad53e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/BigDecimalDeserializer.java
@@ -48,9 +48,19 @@
package com.alibaba.com.caucho.hessian.io;
-import java.util.logging.Logger;
+import java.math.BigDecimal;
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Deserializing a BigDecimal
+ */
+public class BigDecimalDeserializer extends AbstractStringValueDeserializer {
+ @Override
+ public Class<?> getType() {
+ return BigDecimal.class;
+ }
+
+ @Override
+ protected Object create(String value) {
+ return new BigDecimal(value);
+ }
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BitSetSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/BitSetSerializer.java
index 9b7c56e..bc5099a 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BitSetSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/BitSetSerializer.java
@@ -48,6 +48,7 @@
package com.alibaba.com.caucho.hessian.io;
+
import java.io.IOException;
import java.util.BitSet;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ByteArraySerializer.java
similarity index 77%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/ByteArraySerializer.java
index 72a9822..6f15715 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ByteArraySerializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -51,15 +51,28 @@
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object for known object types.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class ByteArraySerializer extends AbstractSerializer
+ implements ObjectSerializer {
+ public static final ByteArraySerializer SER = new ByteArraySerializer();
+
+ private ByteArraySerializer() {
+ }
+
@Override
- public Object lookup(String type, String url)
+ public Serializer getObjectSerializer() {
+ return this;
+ }
+
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ byte[] data = (byte[]) obj;
+
+ if (data != null)
+ out.writeBytes(data, 0, data.length);
+ else
+ out.writeNull();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ByteHandle.java
similarity index 80%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/ByteHandle.java
index 72a9822..b171633 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ByteHandle.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -48,18 +48,30 @@
package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
+import java.io.Serializable;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Handle for Java Byte objects.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+public class ByteHandle implements Serializable {
+ private byte _value;
+
+ private ByteHandle() {
+ }
+
+ public ByteHandle(byte value) {
+ _value = value;
+ }
+
+ public byte getValue() {
+ return _value;
+ }
+
+ public Object readResolve() {
+ return new Byte(_value);
+ }
+
+ public String toString() {
+ return getClass().getSimpleName() + "[" + _value + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/CalendarSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/CalendarSerializer.java
index 0db6c14..9300ac1 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/CalendarSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/CalendarSerializer.java
@@ -48,29 +48,21 @@
package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
import java.util.Calendar;
/**
* Serializing a calendar.
*/
public class CalendarSerializer extends AbstractSerializer {
- private static CalendarSerializer SERIALIZER = new CalendarSerializer();
+ public static final Serializer SER = new CalendarSerializer();
- public static CalendarSerializer create() {
- return SERIALIZER;
- }
-
+ /**
+ * java.util.Calendar serializes to com.alibaba.com.caucho.hessian.io.CalendarHandle
+ */
@Override
- public void writeObject(Object obj, AbstractHessianOutput out)
- throws IOException {
- if (obj == null)
- out.writeNull();
- else {
- Calendar cal = (Calendar) obj;
+ public Object writeReplace(Object obj) {
+ Calendar cal = (Calendar) obj;
- out.writeObject(new CalendarHandle(cal.getClass(),
- cal.getTimeInMillis()));
- }
+ return new CalendarHandle(cal.getClass(), cal.getTimeInMillis());
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ClassDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ClassDeserializer.java
index 422333c..137aca7 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ClassDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ClassDeserializer.java
@@ -85,12 +85,10 @@
_loader = loader;
}
- @Override
public Class getType() {
return Class.class;
}
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
int ref = in.addRef(null);
@@ -115,9 +113,10 @@
return value;
}
- @Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object readObject(AbstractHessianInput in, Object[] fields)
throws IOException {
+ String[] fieldNames = (String[]) fields;
+
int ref = in.addRef(null);
String name = null;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ClassFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ClassFactory.java
index d64b6fe..d27080d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ClassFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ClassFactory.java
@@ -54,11 +54,9 @@
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -67,28 +65,70 @@
/**
* Loads a class from the classloader.
*/
-public class ClassFactory
-{
+public class ClassFactory {
protected static final Logger log
= Logger.getLogger(ClassFactory.class.getName());
private static final ArrayList<Allow> _staticAllowList;
private static final Map<String, Object> _allowSubClassSet = new ConcurrentHashMap<>();
private static final Map<String, Object> _allowClassSet = new ConcurrentHashMap<>();
+ static {
+ _staticAllowList = new ArrayList<Allow>();
+
+ ClassLoader classLoader = ClassFactory.class.getClassLoader();
+ try {
+ String[] denyClasses = readLines(classLoader.getResourceAsStream("DENY_CLASS"));
+ for (String denyClass : denyClasses) {
+ if (denyClass.startsWith("#")) {
+ continue;
+ }
+ if (denyClass.endsWith(".")) {
+ _staticAllowList.add(new AllowPrefix(denyClass, false));
+ } else {
+ _staticAllowList.add(new Allow(toPattern(denyClass), false));
+ }
+ }
+ } catch (IOException ignore) {
+
+ }
+ }
+
private ClassLoader _loader;
private boolean _isWhitelist;
-
private LinkedList<Allow> _allowList;
- ClassFactory(ClassLoader loader)
- {
+ ClassFactory(ClassLoader loader) {
_loader = loader;
initAllow();
}
+ private static String toPattern(String pattern) {
+ pattern = pattern.replace(".", "\\.");
+ pattern = pattern.replace("*", ".*");
+
+ return pattern;
+ }
+
+ /**
+ * read lines.
+ *
+ * @param is input stream.
+ * @return lines.
+ * @throws IOException If an I/O error occurs
+ */
+ public static String[] readLines(InputStream is) throws IOException {
+ List<String> lines = new ArrayList<String>();
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ lines.add(line);
+ }
+ return lines.toArray(new String[0]);
+ }
+ }
+
public Class<?> load(String className)
- throws ClassNotFoundException
- {
+ throws ClassNotFoundException {
if (isAllow(className)) {
Class<?> aClass = Class.forName(className, false, _loader);
@@ -98,7 +138,7 @@
if (aClass.getInterfaces().length > 0) {
for (Class<?> anInterface : aClass.getInterfaces()) {
- if(!isAllow(anInterface.getName())) {
+ if (!isAllow(anInterface.getName())) {
log.log(Level.SEVERE, className + "'s interfaces: " + anInterface.getName() + " in blacklist or not in whitelist, deserialization with type 'HashMap' instead.");
return HashMap.class;
}
@@ -115,7 +155,7 @@
}
for (Class<?> aSuperClass : allSuperClasses) {
- if(!isAllow(aSuperClass.getName())) {
+ if (!isAllow(aSuperClass.getName())) {
log.log(Level.SEVERE, className + "'s superClass: " + aSuperClass.getName() + " in blacklist or not in whitelist, deserialization with type 'HashMap' instead.");
return HashMap.class;
}
@@ -124,15 +164,13 @@
_allowClassSet.put(className, className);
return aClass;
- }
- else {
+ } else {
log.log(Level.SEVERE, className + " in blacklist or not in whitelist, deserialization with type 'HashMap' instead.");
return HashMap.class;
}
}
- private boolean isAllow(String className)
- {
+ private boolean isAllow(String className) {
LinkedList<Allow> allowList = _allowList;
if (allowList == null) {
@@ -162,8 +200,7 @@
return true;
}
- public void setWhitelist(boolean isWhitelist)
- {
+ public void setWhitelist(boolean isWhitelist) {
_allowClassSet.clear();
_allowSubClassSet.clear();
_isWhitelist = isWhitelist;
@@ -171,8 +208,7 @@
initAllow();
}
- public void allow(String pattern)
- {
+ public void allow(String pattern) {
_allowClassSet.clear();
_allowSubClassSet.clear();
initAllow();
@@ -182,8 +218,7 @@
}
}
- public void deny(String pattern)
- {
+ public void deny(String pattern) {
_allowClassSet.clear();
_allowSubClassSet.clear();
initAllow();
@@ -193,16 +228,7 @@
}
}
- private static String toPattern(String pattern)
- {
- pattern = pattern.replace(".", "\\.");
- pattern = pattern.replace("*", ".*");
-
- return pattern;
- }
-
- private void initAllow()
- {
+ private void initAllow() {
synchronized (this) {
if (_allowList == null) {
_allowList = new LinkedList<Allow>();
@@ -218,18 +244,15 @@
public Allow() {
}
- private Allow(String pattern, boolean isAllow)
- {
+ private Allow(String pattern, boolean isAllow) {
_isAllow = isAllow;
_pattern = Pattern.compile(pattern);
}
- Boolean allow(String className)
- {
+ Boolean allow(String className) {
if (_pattern.matcher(className).matches()) {
return _isAllow;
- }
- else {
+ } else {
return null;
}
}
@@ -239,61 +262,19 @@
private Boolean _isAllow;
private String _prefix;
- private AllowPrefix(String prefix, boolean isAllow)
- {
+ private AllowPrefix(String prefix, boolean isAllow) {
super();
_isAllow = isAllow;
_prefix = prefix;
}
@Override
- Boolean allow(String className)
- {
+ Boolean allow(String className) {
if (className.startsWith(_prefix)) {
return _isAllow;
- }
- else {
+ } else {
return null;
}
}
}
-
- static {
- _staticAllowList = new ArrayList<Allow>();
-
- ClassLoader classLoader = ClassFactory.class.getClassLoader();
- try {
- String[] denyClasses = readLines(classLoader.getResourceAsStream("DENY_CLASS"));
- for (String denyClass : denyClasses) {
- if (denyClass.startsWith("#")) {
- continue;
- }
- if (denyClass.endsWith(".")) {
- _staticAllowList.add(new AllowPrefix(denyClass, false));
- } else {
- _staticAllowList.add(new Allow(toPattern(denyClass), false));
- }
- }
- } catch (IOException ignore) {
-
- }
- }
-
- /**
- * read lines.
- *
- * @param is input stream.
- * @return lines.
- * @throws IOException If an I/O error occurs
- */
- public static String[] readLines(InputStream is) throws IOException {
- List<String> lines = new ArrayList<String>();
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
- String line;
- while ((line = reader.readLine()) != null) {
- lines.add(line);
- }
- return lines.toArray(new String[0]);
- }
- }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ClassSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ClassSerializer.java
index 7529e17..b65411e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ClassSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ClassSerializer.java
@@ -54,7 +54,6 @@
* Serializing a remote object.
*/
public class ClassSerializer extends AbstractSerializer {
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
Class cl = (Class) obj;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
index c9465b6..1138fab 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionDeserializer.java
@@ -67,63 +67,32 @@
_type = type;
}
- @Override
public Class getType() {
return _type;
}
- @Override
public Object readList(AbstractHessianInput in, int length)
throws IOException {
- return readList(in, length, _type);
- }
-
- @Override
- public Object readList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
Collection list = createList();
in.addRef(list);
- Deserializer deserializer = null;
-
- SerializerFactory factory = findSerializerFactory(in);
- if (expectType != null) {
- deserializer = factory.getDeserializer(expectType.getName());
- }
-
- while (!in.isEnd()) {
- list.add(deserializer != null ? deserializer.readObject(in) : in.readObject());
- }
-
+ while (!in.isEnd())
+ list.add(in.readObject());
in.readEnd();
return list;
}
- @Override
public Object readLengthList(AbstractHessianInput in, int length)
throws IOException {
- return readList(in, length, null);
- }
-
- @Override
- public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
Collection list = createList();
in.addRef(list);
- Deserializer deserializer = null;
-
- SerializerFactory factory = findSerializerFactory(in);
- if (expectType != null) {
- deserializer = factory.getDeserializer(expectType.getName());
- }
-
- for (; length > 0; length--) {
- list.add(deserializer != null ? deserializer.readObject(in) : in.readObject());
- }
-
+ for (; length > 0; length--)
+ list.add(in.readObject());
return list;
}
@@ -161,8 +130,7 @@
return list;
}
- public String toString()
- {
+ public String toString() {
return getClass().getSimpleName() + "[" + _type + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionSerializer.java
index abc92d4..9951ab0 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/CollectionSerializer.java
@@ -74,7 +74,6 @@
_sendJavaType = sendJavaType;
}
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
if (out.addRef(obj))
@@ -83,7 +82,27 @@
Collection list = (Collection) obj;
Class cl = obj.getClass();
- boolean hasEnd = out.writeListBegin(list.size(), obj.getClass().getName());
+ boolean hasEnd;
+
+ if (cl.equals(ArrayList.class)
+ || !Serializable.class.isAssignableFrom(cl)) {
+ hasEnd = out.writeListBegin(list.size(), null);
+ } else if (!_sendJavaType) {
+ hasEnd = false;
+
+ // hessian/3a19
+ for (; cl != null; cl = cl.getSuperclass()) {
+ if (cl.getName().startsWith("java.")) {
+ hasEnd = out.writeListBegin(list.size(), cl.getName());
+ break;
+ }
+ }
+
+ if (cl == null)
+ hasEnd = out.writeListBegin(list.size(), null);
+ } else {
+ hasEnd = out.writeListBegin(list.size(), obj.getClass().getName());
+ }
Iterator iter = list.iterator();
while (iter.hasNext()) {
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java
new file mode 100644
index 0000000..b89d994
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import com.alibaba.com.caucho.hessian.HessianException;
+
+import java.io.InputStream;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * The classloader-specific Factory for returning serialization
+ */
+public class ContextSerializerFactory {
+ private static final Logger log
+ = Logger.getLogger(ContextSerializerFactory.class.getName());
+ private static final WeakHashMap<ClassLoader, SoftReference<ContextSerializerFactory>>
+ _contextRefMap
+ = new WeakHashMap<ClassLoader, SoftReference<ContextSerializerFactory>>();
+ private static final ClassLoader _systemClassLoader;
+ private static Deserializer OBJECT_DESERIALIZER
+ = new BasicDeserializer(BasicDeserializer.OBJECT);
+ private static HashMap<String, Serializer> _staticSerializerMap;
+ private static HashMap<String, Deserializer> _staticDeserializerMap;
+ private static HashMap _staticClassNameMap;
+
+ static {
+ _staticSerializerMap = new HashMap();
+ _staticDeserializerMap = new HashMap();
+ _staticClassNameMap = new HashMap();
+
+ FieldDeserializer2Factory fieldFactory = FieldDeserializer2Factory.create();
+
+ addBasic(void.class, "void", BasicSerializer.NULL);
+
+ addBasic(Boolean.class, "boolean", BasicSerializer.BOOLEAN);
+ addBasic(Byte.class, "byte", BasicSerializer.BYTE);
+ addBasic(Short.class, "short", BasicSerializer.SHORT);
+ addBasic(Integer.class, "int", BasicSerializer.INTEGER);
+ addBasic(Long.class, "long", BasicSerializer.LONG);
+ addBasic(Float.class, "float", BasicSerializer.FLOAT);
+ addBasic(Double.class, "double", BasicSerializer.DOUBLE);
+ addBasic(Character.class, "char", BasicSerializer.CHARACTER_OBJECT);
+ addBasic(String.class, "string", BasicSerializer.STRING);
+ addBasic(Object.class, "object", BasicSerializer.OBJECT);
+ addBasic(java.util.Date.class, "date", BasicSerializer.DATE);
+
+ addBasic(boolean.class, "boolean", BasicSerializer.BOOLEAN);
+ addBasic(byte.class, "byte", BasicSerializer.BYTE);
+ addBasic(short.class, "short", BasicSerializer.SHORT);
+ addBasic(int.class, "int", BasicSerializer.INTEGER);
+ addBasic(long.class, "long", BasicSerializer.LONG);
+ addBasic(float.class, "float", BasicSerializer.FLOAT);
+ addBasic(double.class, "double", BasicSerializer.DOUBLE);
+ addBasic(char.class, "char", BasicSerializer.CHARACTER);
+
+ addBasic(boolean[].class, "[boolean", BasicSerializer.BOOLEAN_ARRAY);
+ addBasic(byte[].class, "[byte", BasicSerializer.BYTE_ARRAY);
+ _staticSerializerMap.put(byte[].class.getName(), ByteArraySerializer.SER);
+ addBasic(short[].class, "[short", BasicSerializer.SHORT_ARRAY);
+ addBasic(int[].class, "[int", BasicSerializer.INTEGER_ARRAY);
+ addBasic(long[].class, "[long", BasicSerializer.LONG_ARRAY);
+ addBasic(float[].class, "[float", BasicSerializer.FLOAT_ARRAY);
+ addBasic(double[].class, "[double", BasicSerializer.DOUBLE_ARRAY);
+ addBasic(char[].class, "[char", BasicSerializer.CHARACTER_ARRAY);
+ addBasic(String[].class, "[string", BasicSerializer.STRING_ARRAY);
+ addBasic(Object[].class, "[object", BasicSerializer.OBJECT_ARRAY);
+
+ Deserializer objectDeserializer = new JavaDeserializer(Object.class, fieldFactory);
+ _staticDeserializerMap.put("object", objectDeserializer);
+ _staticClassNameMap.put("object", objectDeserializer);
+
+ _staticSerializerMap.put(Class.class.getName(), new ClassSerializer());
+
+ _staticDeserializerMap.put(Number.class.getName(), new BasicDeserializer(BasicSerializer.NUMBER));
+
+ /*
+ for (Class cl : new Class[] { BigDecimal.class, File.class, ObjectName.class }) {
+ _staticSerializerMap.put(cl, StringValueSerializer.SER);
+ _staticDeserializerMap.put(cl, new StringValueDeserializer(cl));
+ }
+
+ _staticSerializerMap.put(ObjectName.class, StringValueSerializer.SER);
+ try {
+ _staticDeserializerMap.put(ObjectName.class,
+ new StringValueDeserializer(ObjectName.class));
+ } catch (Throwable e) {
+ }
+ */
+
+ _staticSerializerMap.put(InetAddress.class.getName(),
+ InetAddressSerializer.create());
+
+ _staticSerializerMap.put(java.sql.Date.class.getName(),
+ new SqlDateSerializer());
+ _staticSerializerMap.put(java.sql.Time.class.getName(),
+ new SqlDateSerializer());
+ _staticSerializerMap.put(java.sql.Timestamp.class.getName(),
+ new SqlDateSerializer());
+
+ _staticDeserializerMap.put(java.sql.Date.class.getName(),
+ new SqlDateDeserializer(java.sql.Date.class));
+ _staticDeserializerMap.put(java.sql.Time.class.getName(),
+ new SqlDateDeserializer(java.sql.Time.class));
+ _staticDeserializerMap.put(java.sql.Timestamp.class.getName(),
+ new SqlDateDeserializer(java.sql.Timestamp.class));
+
+ // hessian/3bb5
+ _staticDeserializerMap.put(StackTraceElement.class.getName(),
+ new StackTraceElementDeserializer(fieldFactory));
+
+ ClassLoader systemClassLoader = null;
+ try {
+ systemClassLoader = ClassLoader.getSystemClassLoader();
+ } catch (Exception e) {
+ }
+
+ _systemClassLoader = systemClassLoader;
+ }
+
+ private final HashSet<String> _serializerFiles = new HashSet<String>();
+ private final HashSet<String> _deserializerFiles = new HashSet<String>();
+ private final HashMap<String, Serializer> _serializerClassMap
+ = new HashMap<String, Serializer>();
+ private final ConcurrentHashMap<String, Serializer> _customSerializerMap
+ = new ConcurrentHashMap<String, Serializer>();
+ private final HashMap<Class<?>, Serializer> _serializerInterfaceMap
+ = new HashMap<Class<?>, Serializer>();
+ private final HashMap<String, Deserializer> _deserializerClassMap
+ = new HashMap<String, Deserializer>();
+ private final HashMap<String, Deserializer> _deserializerClassNameMap
+ = new HashMap<String, Deserializer>();
+ private final ConcurrentHashMap<String, Deserializer> _customDeserializerMap
+ = new ConcurrentHashMap<String, Deserializer>();
+ private final HashMap<Class<?>, Deserializer> _deserializerInterfaceMap
+ = new HashMap<Class<?>, Deserializer>();
+ private ContextSerializerFactory _parent;
+ private WeakReference<ClassLoader> _loaderRef;
+
+ public ContextSerializerFactory(ContextSerializerFactory parent,
+ ClassLoader loader) {
+ if (loader == null)
+ loader = _systemClassLoader;
+
+ _loaderRef = new WeakReference<ClassLoader>(loader);
+
+ init();
+ }
+
+ public static ContextSerializerFactory create() {
+ return create(Thread.currentThread().getContextClassLoader());
+ }
+
+ public static ContextSerializerFactory create(ClassLoader loader) {
+ synchronized (_contextRefMap) {
+ SoftReference<ContextSerializerFactory> factoryRef
+ = _contextRefMap.get(loader);
+
+ ContextSerializerFactory factory = null;
+
+ if (factoryRef != null)
+ factory = factoryRef.get();
+
+ if (factory == null) {
+ ContextSerializerFactory parent = null;
+
+ if (loader != null)
+ parent = create(loader.getParent());
+
+ factory = new ContextSerializerFactory(parent, loader);
+ factoryRef = new SoftReference<ContextSerializerFactory>(factory);
+
+ _contextRefMap.put(loader, factoryRef);
+ }
+
+ return factory;
+ }
+ }
+
+ private static void addBasic(Class cl, String typeName, int type) {
+ _staticSerializerMap.put(cl.getName(), new BasicSerializer(type));
+
+ Deserializer deserializer = new BasicDeserializer(type);
+ _staticDeserializerMap.put(cl.getName(), deserializer);
+ _staticClassNameMap.put(typeName, deserializer);
+ }
+
+ public ClassLoader getClassLoader() {
+ WeakReference<ClassLoader> loaderRef = _loaderRef;
+
+ if (loaderRef != null)
+ return loaderRef.get();
+ else
+ return null;
+ }
+
+ /**
+ * Returns the serializer for a given class.
+ */
+ public Serializer getSerializer(String className) {
+ Serializer serializer = _serializerClassMap.get(className);
+
+ if (serializer == AbstractSerializer.NULL)
+ return null;
+ else
+ return serializer;
+ }
+
+ /**
+ * Returns a custom serializer the class
+ *
+ * @param cl the class of the object that needs to be serialized.
+ * @return a serializer object for the serialization.
+ */
+ public Serializer getCustomSerializer(Class cl) {
+ Serializer serializer = _customSerializerMap.get(cl.getName());
+
+ if (serializer == AbstractSerializer.NULL)
+ return null;
+ else if (serializer != null)
+ return serializer;
+
+ try {
+ Class serClass = Class.forName(cl.getName() + "HessianSerializer",
+ false, cl.getClassLoader());
+
+ Serializer ser = (Serializer) serClass.newInstance();
+
+ _customSerializerMap.put(cl.getName(), ser);
+
+ return ser;
+ } catch (ClassNotFoundException e) {
+ log.log(Level.ALL, e.toString(), e);
+ } catch (Exception e) {
+ throw new HessianException(e);
+ }
+
+ _customSerializerMap.put(cl.getName(), AbstractSerializer.NULL);
+
+ return null;
+ }
+
+ /**
+ * Returns the deserializer for a given class.
+ */
+ public Deserializer getDeserializer(String className) {
+ Deserializer deserializer = _deserializerClassMap.get(className);
+
+ if (deserializer != null && deserializer != AbstractDeserializer.NULL) {
+ return deserializer;
+ }
+
+ deserializer = _deserializerInterfaceMap.get(className);
+
+ if (deserializer != null && deserializer != AbstractDeserializer.NULL) {
+ return deserializer;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a custom deserializer the class
+ *
+ * @param cl the class of the object that needs to be deserialized.
+ * @return a deserializer object for the deserialization.
+ */
+ public Deserializer getCustomDeserializer(Class cl) {
+ Deserializer deserializer = _customDeserializerMap.get(cl.getName());
+
+ if (deserializer == AbstractDeserializer.NULL)
+ return null;
+ else if (deserializer != null)
+ return deserializer;
+
+ try {
+ Class serClass = Class.forName(cl.getName() + "HessianDeserializer",
+ false, cl.getClassLoader());
+
+ Deserializer ser = (Deserializer) serClass.newInstance();
+
+ _customDeserializerMap.put(cl.getName(), ser);
+
+ return ser;
+ } catch (ClassNotFoundException e) {
+ log.log(Level.ALL, e.toString(), e);
+ } catch (Exception e) {
+ throw new HessianException(e);
+ }
+
+ _customDeserializerMap.put(cl.getName(), AbstractDeserializer.NULL);
+
+ return null;
+ }
+
+ /**
+ * Initialize the factory
+ */
+ private void init() {
+ if (_parent != null) {
+ _serializerFiles.addAll(_parent._serializerFiles);
+ _deserializerFiles.addAll(_parent._deserializerFiles);
+
+ _serializerClassMap.putAll(_parent._serializerClassMap);
+ _deserializerClassMap.putAll(_parent._deserializerClassMap);
+ }
+
+ if (_parent == null) {
+ _serializerClassMap.putAll(_staticSerializerMap);
+ _deserializerClassMap.putAll(_staticDeserializerMap);
+ _deserializerClassNameMap.putAll(_staticClassNameMap);
+ }
+
+ HashMap<Class, Class> classMap;
+
+ classMap = new HashMap<Class, Class>();
+ initSerializerFiles("META-INF/dubbo/hessian/serializers",
+ _serializerFiles,
+ classMap,
+ Serializer.class);
+
+ for (Map.Entry<Class, Class> entry : classMap.entrySet()) {
+ try {
+ Serializer ser = (Serializer) entry.getValue().newInstance();
+
+ if (entry.getKey().isInterface())
+ _serializerInterfaceMap.put(entry.getKey(), ser);
+ else
+ _serializerClassMap.put(entry.getKey().getName(), ser);
+ } catch (Exception e) {
+ throw new HessianException(e);
+ }
+ }
+
+ classMap = new HashMap<Class, Class>();
+ initSerializerFiles("META-INF/dubbo/hessian/deserializers",
+ _deserializerFiles,
+ classMap,
+ Deserializer.class);
+
+ for (Map.Entry<Class, Class> entry : classMap.entrySet()) {
+ try {
+ Deserializer ser = (Deserializer) entry.getValue().newInstance();
+
+ if (entry.getKey().isInterface())
+ _deserializerInterfaceMap.put(entry.getKey(), ser);
+ else {
+ _deserializerClassMap.put(entry.getKey().getName(), ser);
+ }
+ } catch (Exception e) {
+ throw new HessianException(e);
+ }
+ }
+ }
+
+ private void initSerializerFiles(String fileName,
+ HashSet<String> fileList,
+ HashMap<Class, Class> classMap,
+ Class type) {
+ try {
+ ClassLoader classLoader = getClassLoader();
+
+ // on systems with the security manager enabled, the system classloader
+ // is null
+ if (classLoader == null)
+ return;
+
+ Enumeration iter;
+
+ iter = classLoader.getResources(fileName);
+ while (iter.hasMoreElements()) {
+ URL url = (URL) iter.nextElement();
+
+ if (fileList.contains(url.toString()))
+ continue;
+
+ fileList.add(url.toString());
+
+ InputStream is = null;
+ try {
+ is = url.openStream();
+
+ Properties props = new Properties();
+ props.load(is);
+
+ for (Map.Entry entry : props.entrySet()) {
+ String apiName = (String) entry.getKey();
+ String serializerName = (String) entry.getValue();
+
+ Class apiClass = null;
+ Class serializerClass = null;
+
+ try {
+ apiClass = Class.forName(apiName, false, classLoader);
+ } catch (ClassNotFoundException e) {
+ log.fine(url + ": " + apiName + " is not available in this context: " + getClassLoader());
+ continue;
+ }
+
+ try {
+ serializerClass = Class.forName(serializerName, false, classLoader);
+ } catch (ClassNotFoundException e) {
+ log.fine(url + ": " + serializerName + " is not available in this context: " + getClassLoader());
+ continue;
+ }
+
+ if (!type.isAssignableFrom(serializerClass))
+ throw new HessianException(url + ": " + serializerClass.getName() + " is invalid because it does not implement " + type.getName());
+
+ classMap.put(apiClass, serializerClass);
+ }
+ } finally {
+ if (is != null)
+ is.close();
+ }
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new HessianException(e);
+ }
+ }
+}
+
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java
index d8b6824..9008b8e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/Deserializer.java
@@ -51,11 +51,14 @@
import java.io.IOException;
/**
- * Deserializing an object.
- *
+ * Deserializing an object. Custom deserializers should extend
+ * from AbstractDeserializer to avoid issues with signature
+ * changes.
*/
public interface Deserializer {
- public Class getType();
+ public Class<?> getType();
+
+ public boolean isReadResolve();
public Object readObject(AbstractHessianInput in)
throws IOException;
@@ -63,47 +66,43 @@
public Object readList(AbstractHessianInput in, int length)
throws IOException;
- /**
- * deserialize list object from expect type.
- *
- * @param in
- * @param length
- * @param expectType
- * @return
- * @throws IOException
- */
- public Object readList(AbstractHessianInput in, int length, Class<?> expectType)
- throws IOException;
-
public Object readLengthList(AbstractHessianInput in, int length)
throws IOException;
- /**
- * deserialize list object from expect type.
- *
- * @param in
- * @param length
- * @param expectType
- * @return
- * @throws IOException
- */
- public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType)
- throws IOException;
-
public Object readMap(AbstractHessianInput in)
throws IOException;
/**
- * deserialize map object from expect key and value type.
- * @param in
- * @param expectKeyType
- * @param expectValueType
- * @return
+ * Creates an empty array for the deserializers field
+ * entries.
+ *
+ * @param len number of fields to be read
+ * @return empty array of the proper field type.
+ */
+ public Object[] createFields(int len);
+
+ /**
+ * Returns the deserializer's field reader for the given name.
+ *
+ * @param name the field name
+ * @return the deserializer's internal field reader
+ */
+ public Object createField(String name);
+
+ /**
+ * Reads the object from the input stream, given the field
+ * definition.
+ *
+ * @param in the input stream
+ * @param fields the deserializer's own field marshal
+ * @return the new object
* @throws IOException
*/
- public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType)
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
throws IOException;
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object readObject(AbstractHessianInput in,
+ String[] fieldNames)
throws IOException;
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumDeserializer.java
index d1876a8..235bb32 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumDeserializer.java
@@ -75,12 +75,10 @@
}
}
- @Override
public Class getType() {
return _enumType;
}
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
String name = null;
@@ -104,8 +102,9 @@
}
@Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object readObject(AbstractHessianInput in, Object[] fields)
throws IOException {
+ String[] fieldNames = (String[]) fields;
String name = null;
for (int i = 0; i < fieldNames.length; i++) {
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSerializer.java
index 6ebf138..0835cc8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSerializer.java
@@ -69,13 +69,12 @@
}
}
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
if (out.addRef(obj))
return;
- Class cl = obj.getClass();
+ Class<?> cl = obj.getClass();
if (!cl.isEnum() && cl.getSuperclass().isEnum())
cl = cl.getSuperclass();
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationDeserializer.java
index b912fa8..912e492 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationDeserializer.java
@@ -64,7 +64,6 @@
return _deserializer;
}
- @Override
public Object readList(AbstractHessianInput in, int length)
throws IOException {
Vector list = new Vector();
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationSerializer.java
index 0665132..aa8d25c 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/EnumerationSerializer.java
@@ -64,7 +64,6 @@
return _serializer;
}
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
Enumeration iter = (Enumeration) obj;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2.java
similarity index 85%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2.java
index be505fb..467ea9f 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -48,9 +48,12 @@
package com.alibaba.com.caucho.hessian.io;
-import java.util.logging.Logger;
+import java.io.IOException;
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Serializing an object for known object types.
+ */
+public interface FieldDeserializer2 {
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException;
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2Factory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2Factory.java
new file mode 100644
index 0000000..28c8660
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2Factory.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class FieldDeserializer2Factory {
+ private static final Logger log
+ = Logger.getLogger(JavaDeserializer.class.getName());
+
+ public static FieldDeserializer2Factory create() {
+ boolean isEnableUnsafeSerializer = (UnsafeSerializer.isEnabled()
+ && UnsafeDeserializer.isEnabled());
+
+ if (isEnableUnsafeSerializer) {
+ return new FieldDeserializer2FactoryUnsafe();
+ } else {
+ return new FieldDeserializer2Factory();
+ }
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected static Object getParamArg(Class<?> cl) {
+ if (!cl.isPrimitive())
+ return null;
+ else if (boolean.class.equals(cl))
+ return Boolean.FALSE;
+ else if (byte.class.equals(cl))
+ return new Byte((byte) 0);
+ else if (short.class.equals(cl))
+ return new Short((short) 0);
+ else if (char.class.equals(cl))
+ return new Character((char) 0);
+ else if (int.class.equals(cl))
+ return Integer.valueOf(0);
+ else if (long.class.equals(cl))
+ return Long.valueOf(0);
+ else if (float.class.equals(cl))
+ return Float.valueOf(0);
+ else if (double.class.equals(cl))
+ return Double.valueOf(0);
+ else
+ throw new UnsupportedOperationException();
+ }
+
+ static void logDeserializeError(Field field, Object obj, Object value,
+ Throwable e)
+ throws IOException {
+ String fieldName = (field.getDeclaringClass().getName()
+ + "." + field.getName());
+
+ if (e instanceof HessianFieldException)
+ throw (HessianFieldException) e;
+ else if (e instanceof IOException)
+ throw new HessianFieldException(fieldName + ": " + e.getMessage(), e);
+
+ if (value != null)
+ throw new HessianFieldException(fieldName + ": " + value.getClass().getName()
+ + " cannot be assigned to '" + field.getType().getName() + "'", e);
+ else
+ throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ FieldDeserializer2 create(Field field) {
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers())) {
+ return NullFieldDeserializer.DESER;
+ }
+
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ field.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ Class<?> type = field.getType();
+ FieldDeserializer2 deser;
+
+ if (String.class.equals(type))
+ deser = new StringFieldDeserializer(field);
+ else if (byte.class.equals(type)) {
+ deser = new ByteFieldDeserializer(field);
+ } else if (short.class.equals(type)) {
+ deser = new ShortFieldDeserializer(field);
+ } else if (int.class.equals(type)) {
+ deser = new IntFieldDeserializer(field);
+ } else if (long.class.equals(type)) {
+ deser = new LongFieldDeserializer(field);
+ } else if (float.class.equals(type)) {
+ deser = new FloatFieldDeserializer(field);
+ } else if (double.class.equals(type)) {
+ deser = new DoubleFieldDeserializer(field);
+ } else if (boolean.class.equals(type)) {
+ deser = new BooleanFieldDeserializer(field);
+ } else if (java.sql.Date.class.equals(type)) {
+ deser = new SqlDateFieldDeserializer(field);
+ } else if (java.sql.Timestamp.class.equals(type)) {
+ deser = new SqlTimestampFieldDeserializer(field);
+ } else if (java.sql.Time.class.equals(type)) {
+ deser = new SqlTimeFieldDeserializer(field);
+ } else {
+ deser = new ObjectFieldDeserializer(field);
+ }
+
+ return deser;
+ }
+
+ static class NullFieldDeserializer implements FieldDeserializer2 {
+ static NullFieldDeserializer DESER = new NullFieldDeserializer();
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ in.readObject();
+ }
+ }
+
+ static class ObjectFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ ObjectFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ Object value = null;
+
+ try {
+ value = in.readObject(_field.getType());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class BooleanFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ BooleanFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ boolean value = false;
+
+ try {
+ value = in.readBoolean();
+
+ _field.setBoolean(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ByteFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ ByteFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setByte(obj, (byte) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ShortFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ ShortFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setShort(obj, (short) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class IntFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ IntFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setInt(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class LongFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ LongFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ long value = 0;
+
+ try {
+ value = in.readLong();
+
+ _field.setLong(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class FloatFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ FloatFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _field.setFloat(obj, (float) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class DoubleFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ DoubleFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _field.setDouble(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class StringFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ StringFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ String value = null;
+
+ try {
+ value = in.readString();
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlDateFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ SqlDateFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Date value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+
+ if (date != null) {
+ value = new java.sql.Date(date.getTime());
+
+ _field.set(obj, value);
+ } else {
+ _field.set(obj, null);
+ }
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimestampFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ SqlTimestampFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Timestamp value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+
+ if (date != null) {
+ value = new java.sql.Timestamp(date.getTime());
+
+ _field.set(obj, value);
+ } else {
+ _field.set(obj, null);
+ }
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimeFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+
+ SqlTimeFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Time value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+
+ if (date != null) {
+ value = new java.sql.Time(date.getTime());
+
+ _field.set(obj, value);
+ } else {
+ _field.set(obj, null);
+ }
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2FactoryUnsafe.java b/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2FactoryUnsafe.java
new file mode 100644
index 0000000..8aae28f
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/FieldDeserializer2FactoryUnsafe.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import sun.misc.Unsafe;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class FieldDeserializer2FactoryUnsafe extends FieldDeserializer2Factory {
+ private static final Logger log
+ = Logger.getLogger(JavaDeserializer.class.getName());
+
+ private static boolean _isEnabled;
+ @SuppressWarnings("restriction")
+ private static Unsafe _unsafe;
+
+ static {
+ boolean isEnabled = false;
+
+ try {
+ Class<?> unsafe = Class.forName("sun.misc.Unsafe");
+ Field theUnsafe = null;
+ for (Field field : unsafe.getDeclaredFields()) {
+ if (field.getName().equals("theUnsafe"))
+ theUnsafe = field;
+ }
+
+ if (theUnsafe != null) {
+ theUnsafe.setAccessible(true);
+ _unsafe = (Unsafe) theUnsafe.get(null);
+ }
+
+ isEnabled = _unsafe != null;
+
+ String unsafeProp = System.getProperty("com.caucho.hessian.unsafe");
+
+ if ("false".equals(unsafeProp))
+ isEnabled = false;
+ } catch (Throwable e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ _isEnabled = isEnabled;
+ }
+
+ static void logDeserializeError(Field field, Object obj, Object value,
+ Throwable e)
+ throws IOException {
+ String fieldName = (field.getDeclaringClass().getName()
+ + "." + field.getName());
+
+ if (e instanceof HessianFieldException)
+ throw (HessianFieldException) e;
+ else if (e instanceof IOException)
+ throw new HessianFieldException(fieldName + ": " + e.getMessage(), e);
+
+ if (value != null)
+ throw new HessianFieldException(fieldName + ": " + value.getClass().getName()
+ + " cannot be assigned to '" + field.getType().getName() + "'", e);
+ else
+ throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ @Override
+ public FieldDeserializer2 create(Field field) {
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers())) {
+ return NullFieldDeserializer.DESER;
+ }
+
+ /*
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ field.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ */
+
+ Class<?> type = field.getType();
+ FieldDeserializer2 deser;
+
+ if (String.class.equals(type)) {
+ deser = new StringFieldDeserializer(field);
+ } else if (byte.class.equals(type)) {
+ deser = new ByteFieldDeserializer(field);
+ } else if (char.class.equals(type)) {
+ deser = new CharFieldDeserializer(field);
+ } else if (short.class.equals(type)) {
+ deser = new ShortFieldDeserializer(field);
+ } else if (int.class.equals(type)) {
+ deser = new IntFieldDeserializer(field);
+ } else if (long.class.equals(type)) {
+ deser = new LongFieldDeserializer(field);
+ } else if (float.class.equals(type)) {
+ deser = new FloatFieldDeserializer(field);
+ } else if (double.class.equals(type)) {
+ deser = new DoubleFieldDeserializer(field);
+ } else if (boolean.class.equals(type)) {
+ deser = new BooleanFieldDeserializer(field);
+ } else if (java.sql.Date.class.equals(type)) {
+ deser = new SqlDateFieldDeserializer(field);
+ } else if (java.sql.Timestamp.class.equals(type)) {
+ deser = new SqlTimestampFieldDeserializer(field);
+ } else if (java.sql.Time.class.equals(type)) {
+ deser = new SqlTimeFieldDeserializer(field);
+ } else {
+ deser = new ObjectFieldDeserializer(field);
+ }
+
+ return deser;
+ }
+
+ static class NullFieldDeserializer implements FieldDeserializer2 {
+ static NullFieldDeserializer DESER = new NullFieldDeserializer();
+
+ @Override
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ in.readObject();
+ }
+ }
+
+ static class ObjectFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ ObjectFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ Object value = null;
+
+ try {
+ value = in.readObject(_field.getType());
+
+ _unsafe.putObject(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class BooleanFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ BooleanFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ boolean value = false;
+
+ try {
+ value = in.readBoolean();
+
+ _unsafe.putBoolean(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ByteFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ ByteFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _unsafe.putByte(obj, _offset, (byte) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class CharFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ CharFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ String value = null;
+
+ try {
+ value = in.readString();
+
+ char ch;
+
+ if (value != null && value.length() > 0)
+ ch = value.charAt(0);
+ else
+ ch = 0;
+
+ _unsafe.putChar(obj, _offset, ch);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ShortFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ ShortFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _unsafe.putShort(obj, _offset, (short) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class IntFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ IntFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _unsafe.putInt(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class LongFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ LongFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ long value = 0;
+
+ try {
+ value = in.readLong();
+
+ _unsafe.putLong(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class FloatFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ FloatFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _unsafe.putDouble(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class DoubleFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ DoubleFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _unsafe.putDouble(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class StringFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ StringFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ String value = null;
+
+ try {
+ value = in.readString();
+
+ _unsafe.putObject(obj, _offset, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlDateFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ SqlDateFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Date value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+
+ if (date != null) {
+ value = new java.sql.Date(date.getTime());
+
+ _unsafe.putObject(obj, _offset, value);
+ } else {
+ _unsafe.putObject(obj, _offset, null);
+ }
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimestampFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ SqlTimestampFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Timestamp value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+
+ if (date != null) {
+ value = new java.sql.Timestamp(date.getTime());
+
+ _unsafe.putObject(obj, _offset, value);
+ } else {
+ _unsafe.putObject(obj, _offset, null);
+ }
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimeFieldDeserializer implements FieldDeserializer2 {
+ private final Field _field;
+ private final long _offset;
+
+ @SuppressWarnings("restriction")
+ SqlTimeFieldDeserializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(_field);
+ }
+
+ @SuppressWarnings("restriction")
+ public void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Time value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+
+ if (date != null) {
+ value = new java.sql.Time(date.getTime());
+
+ _unsafe.putObject(obj, _offset, value);
+ } else {
+ _unsafe.putObject(obj, _offset, null);
+ }
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/FileDeserializer.java
similarity index 88%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/FileDeserializer.java
index be505fb..82bf8be 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/FileDeserializer.java
@@ -48,9 +48,19 @@
package com.alibaba.com.caucho.hessian.io;
-import java.util.logging.Logger;
+import java.io.File;
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Deserializing a File
+ */
+public class FileDeserializer extends AbstractStringValueDeserializer {
+ @Override
+ public Class getType() {
+ return File.class;
+ }
+
+ @Override
+ protected Object create(String value) {
+ return new File(value);
+ }
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/FloatHandle.java
similarity index 78%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/FloatHandle.java
index 72a9822..a790285 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/FloatHandle.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -48,18 +48,30 @@
package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
+import java.io.Serializable;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Handle for Java Float objects.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+public class FloatHandle implements Serializable {
+ private double _value;
+
+ private FloatHandle() {
+ }
+
+ public FloatHandle(float value) {
+ _value = value;
+ }
+
+ public double getValue() {
+ return _value;
+ }
+
+ public Object readResolve() {
+ return Double.parseDouble(String.valueOf(((Number) _value).floatValue()));
+ }
+
+ public String toString() {
+ return getClass().getSimpleName() + "[" + _value + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
index 0466396..a09bbbf 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Input.java
@@ -57,17 +57,15 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Input stream for Hessian requests.
- * <p>
+ *
* <p>HessianInput is unbuffered, so any client needs to provide
* its own buffering.
- * <p>
+ *
* <pre>
* InputStream is = ...; // from http connection
* HessianInput in = new HessianInput(is);
@@ -84,38 +82,34 @@
private static final Logger log
= Logger.getLogger(Hessian2Input.class.getName());
- private static final double D_256 = 1.0 / 256.0;
private static final int END_OF_DATA = -2;
- private static final int SIZE = 256;
+ private static final int SIZE = 1024;
private static final int GAP = 16;
private static Field _detailMessageField;
private static boolean _isCloseStreamOnClose;
-
- static {
- try {
- _detailMessageField = Throwable.class.getDeclaredField("detailMessage");
- _detailMessageField.setAccessible(true);
- } catch (Throwable e) {
- }
- }
-
private final byte[] _buffer = new byte[SIZE];
+ // standard, unmodified factory for deserializing objects
+ protected SerializerFactory _defaultSerializerFactory;
// factory for deserializing objects in the input stream
protected SerializerFactory _serializerFactory;
- protected ArrayList _refs;
- protected ArrayList _classDefs;
- protected ArrayList _types;
+ protected ArrayList<Object> _refs
+ = new ArrayList<Object>();
+ protected ArrayList<ObjectDefinition> _classDefs
+ = new ArrayList<ObjectDefinition>();
+ protected ArrayList<String> _types
+ = new ArrayList<String>();
// the underlying input stream
private InputStream _is;
// a peek character
private int _offset;
private int _length;
- // true for streaming data
- private boolean _isStreaming;
+
// the method for a call
private String _method;
private Throwable _replyFault;
+
private StringBuilder _sbuf = new StringBuilder();
+
// true if this is the last chunk
private boolean _isLastChunk;
// the chunk length
@@ -128,36 +122,62 @@
* @param is the underlying input stream.
*/
public Hessian2Input(InputStream is) {
- _is = is;
+ init(is);
+ }
+
+ private static Field getDetailMessageField() {
+ if (_detailMessageField == null) {
+ try {
+ _detailMessageField = Throwable.class.getDeclaredField("detailMessage");
+ _detailMessageField.setAccessible(true);
+ } catch (Throwable e) {
+ }
+ }
+
+ return _detailMessageField;
}
/**
* Gets the serializer factory.
*/
public SerializerFactory getSerializerFactory() {
+ // the default serializer factory cannot be modified by external
+ // callers
+ if (_serializerFactory == _defaultSerializerFactory) {
+ _serializerFactory = new SerializerFactory();
+ }
+
return _serializerFactory;
}
/**
* Sets the serializer factory.
*/
- @Override
public void setSerializerFactory(SerializerFactory factory) {
_serializerFactory = factory;
}
/**
- * Gets the serializer factory, creating a default if necessary.
+ * Gets the serializer factory.
*/
- public final SerializerFactory findSerializerFactory() {
+ protected final SerializerFactory findSerializerFactory() {
SerializerFactory factory = _serializerFactory;
- if (factory == null)
- _serializerFactory = factory = new SerializerFactory();
+ if (factory == null) {
+ factory = SerializerFactory.createDefault();
+ _defaultSerializerFactory = factory;
+ _serializerFactory = factory;
+ }
return factory;
}
+ public void allow(String pattern) {
+ ClassFactory factory = getSerializerFactory().getClassFactory();
+
+ factory.allow(pattern);
+ }
+
public boolean isCloseStreamOnClose() {
return _isCloseStreamOnClose;
}
@@ -169,7 +189,6 @@
/**
* Returns the calls method
*/
- @Override
public String getMethod() {
return _method;
}
@@ -188,44 +207,19 @@
reset();
}
- public void reset() {
+ public void initPacket(InputStream is) {
+ _is = is;
+
resetReferences();
-
- if (_classDefs != null) {
- _classDefs.clear();
- }
-
- if (_types != null) {
- _types.clear();
- }
-
- _offset = 0;
- _length = 0;
- }
-
- @Override
- public boolean checkAndReadNull() {
- try {
- int tag = read();
- if ('N' == tag) {
- return true;
- }
- if (-1 != tag) {
- _offset--;
- }
- } catch (IOException ignored) {
- }
- return false;
}
/**
* Starts reading the call
- * <p>
+ *
* <pre>
* c major minor
* </pre>
*/
- @Override
public int readCall()
throws IOException {
int tag = read();
@@ -238,7 +232,7 @@
/**
* Starts reading the envelope
- * <p>
+ *
* <pre>
* E major minor
* </pre>
@@ -265,9 +259,9 @@
/**
* Completes reading the envelope
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* Z
* </pre>
@@ -282,14 +276,13 @@
/**
* Starts reading the call
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* string
* </pre>
*/
- @Override
public String readMethod()
throws IOException {
_method = readString();
@@ -299,7 +292,7 @@
/**
* Returns the number of method arguments
- * <p>
+ *
* <pre>
* int
* </pre>
@@ -312,15 +305,14 @@
/**
* Starts reading the call, including the headers.
- * <p>
+ *
* <p>The call expects the following protocol data
- * <p>
+ *
* <pre>
* c major minor
* m b16 b8 method
* </pre>
*/
- @Override
public void startCall()
throws IOException {
readCall();
@@ -328,15 +320,26 @@
readMethod();
}
+ public Object[] readArguments()
+ throws IOException {
+ int len = readInt();
+
+ Object[] args = new Object[len];
+
+ for (int i = 0; i < len; i++)
+ args[i] = readObject();
+
+ return args;
+ }
+
/**
* Completes reading the call
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* </pre>
*/
- @Override
public void completeCall()
throws IOException {
}
@@ -377,14 +380,13 @@
/**
* Starts reading the reply
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* r
* </pre>
*/
- @Override
public void startReply()
throws Throwable {
// XXX: for variable length (?)
@@ -403,9 +405,11 @@
if (detail instanceof Throwable) {
_replyFault = (Throwable) detail;
- if (message != null && _detailMessageField != null) {
+ Field detailMessageField = getDetailMessageField();
+
+ if (message != null && detailMessageField != null) {
try {
- _detailMessageField.set(_replyFault, message);
+ detailMessageField.set(_replyFault, message);
} catch (Throwable e) {
}
}
@@ -422,23 +426,22 @@
/**
* Completes reading the call
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* z
* </pre>
*/
- @Override
public void completeReply()
throws IOException {
}
/**
* Completes reading the call
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* z
* </pre>
@@ -453,20 +456,19 @@
/**
* Reads a header, returning null if there are no headers.
- * <p>
+ *
* <pre>
* H b16 b8 value
* </pre>
*/
- @Override
public String readHeader()
throws IOException {
return null;
}
/**
- * Starts reading the message
- * <p>
+ * Starts reading a packet
+ *
* <pre>
* p major minor
* </pre>
@@ -475,9 +477,10 @@
throws IOException {
int tag = read();
- if (tag != 'p' && tag != 'P') {
+ if (tag == 'p') {
+ } else if (tag == 'P') {
+ } else
throw error("expected Hessian message ('p') at " + codeName(tag));
- }
int major = read();
int minor = read();
@@ -487,9 +490,9 @@
/**
* Completes reading the message
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* z
* </pre>
@@ -504,12 +507,11 @@
/**
* Reads a null
- * <p>
+ *
* <pre>
* N
* </pre>
*/
- @Override
public void readNull()
throws IOException {
int tag = read();
@@ -525,13 +527,12 @@
/**
* Reads a boolean
- * <p>
+ *
* <pre>
* T
* F
* </pre>
*/
- @Override
public boolean readBoolean()
throws IOException {
int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -761,7 +762,7 @@
/**
* Reads a short
- * <p>
+ *
* <pre>
* I b32 b24 b16 b8
* </pre>
@@ -773,12 +774,11 @@
/**
* Reads an integer
- * <p>
+ *
* <pre>
* I b32 b24 b16 b8
* </pre>
*/
- @Override
public final int readInt()
throws IOException {
//int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -993,12 +993,11 @@
/**
* Reads a long
- * <p>
+ *
* <pre>
* L b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
*/
- @Override
public long readLong()
throws IOException {
int tag = read();
@@ -1209,7 +1208,7 @@
/**
* Reads a float
- * <p>
+ *
* <pre>
* D b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
@@ -1221,12 +1220,11 @@
/**
* Reads a double
- * <p>
+ *
* <pre>
* D b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
*/
- @Override
public double readDouble()
throws IOException {
int tag = read();
@@ -1434,12 +1432,11 @@
/**
* Reads a date.
- * <p>
+ *
* <pre>
* T b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
*/
- @Override
public long readUTCDate()
throws IOException {
int tag = read();
@@ -1468,6 +1465,7 @@
_chunkLength = 0;
return -1;
}
+
int tag = read();
switch (tag) {
@@ -1554,6 +1552,14 @@
_chunkLength = tag - 0x00;
break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x30) * 256 + read();
+ break;
+
default:
throw expect("string", tag);
}
@@ -1582,6 +1588,51 @@
_chunkLength = (read() << 8) + read();
break;
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ _isLastChunk = true;
+ _chunkLength = tag - 0x00;
+ break;
+
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x30) * 256 + read();
+ break;
+
default:
throw expect("string", tag);
}
@@ -1600,12 +1651,11 @@
/**
* Reads a string
- * <p>
+ *
* <pre>
* S b16 b8 string value
* </pre>
*/
- @Override
public String readString()
throws IOException {
int tag = read();
@@ -1860,8 +1910,9 @@
_sbuf.setLength(0);
- while ((ch = parseChar()) >= 0)
+ while ((ch = parseChar()) >= 0) {
_sbuf.append((char) ch);
+ }
return _sbuf.toString();
@@ -1886,12 +1937,11 @@
/**
* Reads a byte array
- * <p>
+ *
* <pre>
* B b16 b8 data value
* </pre>
*/
- @Override
public byte[] readBytes()
throws IOException {
int tag = read();
@@ -1900,9 +1950,9 @@
case 'N':
return null;
- case 'B':
+ case BC_BINARY:
case BC_BINARY_CHUNK:
- _isLastChunk = tag == 'B';
+ _isLastChunk = tag == BC_BINARY;
_chunkLength = (read() << 8) + read();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -1934,9 +1984,15 @@
byte[] buffer = new byte[_chunkLength];
- int k = 0;
- while ((data = parseByte()) >= 0)
- buffer[k++] = (byte) data;
+ int offset = 0;
+ while (offset < _chunkLength) {
+ int sublen = read(buffer, 0, _chunkLength - offset);
+
+ if (sublen <= 0)
+ break;
+
+ offset += sublen;
+ }
return buffer;
}
@@ -1949,10 +2005,15 @@
_chunkLength = (tag - 0x34) * 256 + read();
byte[] buffer = new byte[_chunkLength];
- int k = 0;
- while ((data = parseByte()) >= 0) {
- buffer[k++] = (byte) data;
+ int offset = 0;
+ while (offset < _chunkLength) {
+ int sublen = read(buffer, 0, _chunkLength - offset);
+
+ if (sublen <= 0)
+ break;
+
+ offset += sublen;
}
return buffer;
@@ -1986,7 +2047,7 @@
return -1;
case 'B':
- case BC_BINARY_CHUNK:
+ case BC_BINARY_CHUNK: {
_isLastChunk = tag == 'B';
_chunkLength = (read() << 8) + read();
@@ -1998,6 +2059,53 @@
_chunkLength = END_OF_DATA;
return value;
+ }
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f: {
+ _isLastChunk = true;
+ _chunkLength = tag - 0x20;
+
+ int value = parseByte();
+
+ // special code so successive read byte won't
+ // be read as a single object.
+ if (_chunkLength == 0)
+ _chunkLength = END_OF_DATA;
+
+ return value;
+ }
+
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+
+ int value = parseByte();
+
+ // special code so successive read byte won't
+ // be read as a single object.
+ if (_chunkLength == 0)
+ _chunkLength = END_OF_DATA;
+
+ return value;
+ }
default:
throw expect("binary", tag);
@@ -2027,6 +2135,36 @@
_chunkLength = (read() << 8) + read();
break;
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f: {
+ _isLastChunk = true;
+ _chunkLength = tag - 0x20;
+ break;
+ }
+
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+ break;
+ }
+
default:
throw expect("binary", tag);
}
@@ -2072,41 +2210,11 @@
}
/**
- * Reads a fault.
- */
- private HashMap readFault()
- throws IOException {
- HashMap map = new HashMap();
-
- int code = read();
- for (; code > 0 && code != 'Z'; code = read()) {
- _offset--;
-
- Object key = readObject();
- Object value = readObject();
-
- if (key != null && value != null)
- map.put(key, value);
- }
-
- if (code != 'Z')
- throw expect("fault", code);
-
- return map;
- }
-
- /**
* Reads an object from the input stream with an expected type.
*/
- @Override
public Object readObject(Class cl)
throws IOException {
- return readObject(cl, null, null);
- }
-
- @Override
- public Object readObject(Class expectedClass, Class<?>... expectedTypes) throws IOException {
- if (expectedClass == null || expectedClass == Object.class)
+ if (cl == null || cl == Object.class)
return readObject();
int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -2116,13 +2224,9 @@
return null;
case 'H': {
- Deserializer reader = findSerializerFactory().getDeserializer(expectedClass);
+ Deserializer reader = findSerializerFactory().getDeserializer(cl);
- boolean keyValuePair = expectedTypes != null && expectedTypes.length == 2;
- // fix deserialize of short type
- return reader.readMap(this
- , keyValuePair ? expectedTypes[0] : null
- , keyValuePair ? expectedTypes[1] : null);
+ return reader.readMap(this);
}
case 'M': {
@@ -2131,21 +2235,21 @@
// hessian/3bb3
if ("".equals(type)) {
Deserializer reader;
- reader = findSerializerFactory().getDeserializer(expectedClass);
+ reader = findSerializerFactory().getDeserializer(cl);
return reader.readMap(this);
} else {
Deserializer reader;
- reader = findSerializerFactory().getObjectDeserializer(type, expectedClass);
+ reader = findSerializerFactory().getObjectDeserializer(type, cl);
return reader.readMap(this);
}
}
case 'C': {
- readObjectDefinition(expectedClass);
+ readObjectDefinition(cl);
- return readObject(expectedClass);
+ return readObject(cl);
}
case 0x60:
@@ -2170,9 +2274,9 @@
if (ref < 0 || size <= ref)
throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
- ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+ ObjectDefinition def = _classDefs.get(ref);
- return readObjectInstance(expectedClass, def);
+ return readObjectInstance(cl, def);
}
case 'O': {
@@ -2182,16 +2286,16 @@
if (ref < 0 || size <= ref)
throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
- ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+ ObjectDefinition def = _classDefs.get(ref);
- return readObjectInstance(expectedClass, def);
+ return readObjectInstance(cl, def);
}
case BC_LIST_VARIABLE: {
String type = readType();
Deserializer reader;
- reader = findSerializerFactory().getListDeserializer(type, expectedClass);
+ reader = findSerializerFactory().getListDeserializer(type, cl);
Object v = reader.readList(this, -1);
@@ -2203,11 +2307,9 @@
int length = readInt();
Deserializer reader;
- reader = findSerializerFactory().getListDeserializer(type, expectedClass);
+ reader = findSerializerFactory().getListDeserializer(type, cl);
- boolean valueType = expectedTypes != null && expectedTypes.length == 1;
-
- Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+ Object v = reader.readLengthList(this, length);
return v;
}
@@ -2225,24 +2327,18 @@
String type = readType();
Deserializer reader;
- reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+ reader = findSerializerFactory().getListDeserializer(type, cl);
- boolean valueType = expectedTypes != null && expectedTypes.length == 1;
-
- // fix deserialize of short type
- Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+ Object v = reader.readLengthList(this, length);
return v;
}
case BC_LIST_VARIABLE_UNTYPED: {
Deserializer reader;
- reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+ reader = findSerializerFactory().getListDeserializer(null, cl);
- boolean valueType = expectedTypes != null && expectedTypes.length == 1;
-
- // fix deserialize of short type
- Object v = reader.readList(this, -1, valueType ? expectedTypes[0] : null);
+ Object v = reader.readList(this, -1);
return v;
}
@@ -2251,12 +2347,9 @@
int length = readInt();
Deserializer reader;
- reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+ reader = findSerializerFactory().getListDeserializer(null, cl);
- boolean valueType = expectedTypes != null && expectedTypes.length == 1;
-
- // fix deserialize of short type
- Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+ Object v = reader.readLengthList(this, length);
return v;
}
@@ -2272,12 +2365,9 @@
int length = tag - 0x78;
Deserializer reader;
- reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+ reader = findSerializerFactory().getListDeserializer(null, cl);
- boolean valueType = expectedTypes != null && expectedTypes.length == 1;
-
- // fix deserialize of short type
- Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+ Object v = reader.readLengthList(this, length);
return v;
}
@@ -2294,7 +2384,7 @@
// hessian/3b2i vs hessian/3406
// return readObject();
- Object value = findSerializerFactory().getDeserializer(expectedClass).readObject(this);
+ Object value = findSerializerFactory().getDeserializer(cl).readObject(this);
return value;
}
@@ -2302,14 +2392,8 @@
* Reads an arbitrary object from the input stream when the type
* is unknown.
*/
- @Override
public Object readObject()
throws IOException {
- return readObject((List<Class<?>>) null);
- }
-
- @Override
- public Object readObject(List<Class<?>> expectedTypes) throws IOException {
int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
switch (tag) {
@@ -2664,9 +2748,7 @@
Deserializer reader;
reader = findSerializerFactory().getListDeserializer(type, null);
- boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
-
- return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ return reader.readLengthList(this, length);
}
case BC_LIST_FIXED_UNTYPED: {
@@ -2676,9 +2758,7 @@
Deserializer reader;
reader = findSerializerFactory().getListDeserializer(null, null);
- boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
-
- return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ return reader.readLengthList(this, length);
}
// compact fixed list
@@ -2697,9 +2777,7 @@
Deserializer reader;
reader = findSerializerFactory().getListDeserializer(type, null);
- boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
-
- return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ return reader.readLengthList(this, length);
}
// compact fixed untyped list
@@ -2717,22 +2795,11 @@
Deserializer reader;
reader = findSerializerFactory().getListDeserializer(null, null);
- boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
-
- return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ return reader.readLengthList(this, length);
}
case 'H': {
-
- boolean keyValuePair = expectedTypes != null && expectedTypes.size() == 2;
-
- // fix deserialize of short type
- Deserializer reader;
- reader = findSerializerFactory().getDeserializer(Map.class);
-
- return reader.readMap(this
- , keyValuePair ? expectedTypes.get(0) : null
- , keyValuePair ? expectedTypes.get(1) : null);
+ return findSerializerFactory().readMap(this, null);
}
case 'M': {
@@ -2765,10 +2832,11 @@
case 0x6f: {
int ref = tag - 0x60;
- if (_classDefs == null)
- throw error("No classes defined at reference '{0}'" + tag);
+ if (_classDefs.size() <= ref)
+ throw error("No classes defined at reference '"
+ + Integer.toHexString(tag) + "'");
- ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+ ObjectDefinition def = _classDefs.get(ref);
return readObjectInstance(null, def);
}
@@ -2776,7 +2844,10 @@
case 'O': {
int ref = readInt();
- ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+ if (_classDefs.size() <= ref)
+ throw error("Illegal object reference #" + ref);
+
+ ObjectDefinition def = _classDefs.get(ref);
return readObjectInstance(null, def);
}
@@ -2795,94 +2866,59 @@
}
}
- private void parseString(StringBuilder sbuf)
- throws IOException {
- while (true) {
- if (_chunkLength <= 0) {
- if (!parseChunkLength())
- return;
- }
-
- int length = _chunkLength;
- _chunkLength = 0;
-
- while (length-- > 0) {
- sbuf.append((char) parseUTF8Char());
- }
- }
- }
-
/**
* Reads an object definition:
- * <p>
+ *
* <pre>
* O string <int> (string)* <value>*
* </pre>
*/
- private void readObjectDefinition(Class cl)
+ private void readObjectDefinition(Class<?> cl)
throws IOException {
String type = readString();
int len = readInt();
+ SerializerFactory factory = findSerializerFactory();
+
+ Deserializer reader = factory.getObjectDeserializer(type, null);
+
+ Object[] fields = reader.createFields(len);
String[] fieldNames = new String[len];
- for (int i = 0; i < len; i++)
- fieldNames[i] = readString();
- ObjectDefinition def = new ObjectDefinition(type, fieldNames);
+ for (int i = 0; i < len; i++) {
+ String name = readString();
- if (_classDefs == null)
- _classDefs = new ArrayList();
+ fields[i] = reader.createField(name);
+ fieldNames[i] = name;
+ }
+
+ ObjectDefinition def
+ = new ObjectDefinition(type, reader, fields, fieldNames);
_classDefs.add(def);
}
- private Object readObjectInstance(Class cl, ObjectDefinition def)
+ private Object readObjectInstance(Class<?> cl,
+ ObjectDefinition def)
throws IOException {
String type = def.getType();
- String[] fieldNames = def.getFieldNames();
+ Deserializer reader = def.getReader();
+ Object[] fields = def.getFields();
- if (cl != null) {
- Deserializer reader;
- reader = findSerializerFactory().getObjectDeserializer(type, cl);
+ SerializerFactory factory = findSerializerFactory();
- return reader.readObject(this, fieldNames);
+ if (cl != reader.getType() && cl != null) {
+ reader = factory.getObjectDeserializer(type, cl);
+
+ return reader.readObject(this, def.getFieldNames());
} else {
- return findSerializerFactory().readObject(this, type, fieldNames);
+ return reader.readObject(this, fields);
}
}
- private String readLenString()
- throws IOException {
- int len = readInt();
-
- _isLastChunk = true;
- _chunkLength = len;
-
- _sbuf.setLength(0);
- int ch;
- while ((ch = parseChar()) >= 0)
- _sbuf.append((char) ch);
-
- return _sbuf.toString();
- }
-
- private String readLenString(int len)
- throws IOException {
- _isLastChunk = true;
- _chunkLength = len;
-
- _sbuf.setLength(0);
- int ch;
- while ((ch = parseChar()) >= 0)
- _sbuf.append((char) ch);
-
- return _sbuf.toString();
- }
-
/**
* Reads a remote object.
*/
- @Override
public Object readRemote()
throws IOException {
String type = readType();
@@ -2894,16 +2930,16 @@
/**
* Reads a reference.
*/
- @Override
public Object readRef()
throws IOException {
- return _refs.get(parseInt());
+ int value = parseInt();
+
+ return _refs.get(value);
}
/**
* Reads the start of a list.
*/
- @Override
public int readListStart()
throws IOException {
return read();
@@ -2912,7 +2948,6 @@
/**
* Reads the start of a list.
*/
- @Override
public int readMapStart()
throws IOException {
return read();
@@ -2921,7 +2956,6 @@
/**
* Returns true if this is the end of a list or a map.
*/
- @Override
public boolean isEnd()
throws IOException {
int code;
@@ -2941,7 +2975,6 @@
/**
* Reads the end byte.
*/
- @Override
public void readEnd()
throws IOException {
int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -2957,7 +2990,6 @@
/**
* Reads the end byte.
*/
- @Override
public void readMapEnd()
throws IOException {
int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -2969,7 +3001,6 @@
/**
* Reads the end byte.
*/
- @Override
public void readListEnd()
throws IOException {
int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -2994,7 +3025,6 @@
/**
* Adds a list/map reference.
*/
- @Override
public void setRef(int i, Object ref) {
_refs.set(i, ref);
}
@@ -3004,8 +3034,25 @@
*/
@Override
public void resetReferences() {
- if (_refs != null)
- _refs.clear();
+ _refs.clear();
+ }
+
+ public void reset() {
+ resetReferences();
+
+ _classDefs.clear();
+ _types.clear();
+ }
+
+ public void resetBuffer() {
+ int offset = _offset;
+ _offset = 0;
+
+ int length = _length;
+ _length = 0;
+
+ if (length > 0 && offset != length)
+ throw new IllegalStateException("offset=" + offset + " length=" + length);
}
public Object readStreamingObject()
@@ -3031,13 +3078,12 @@
/**
* Parses a type from the stream.
- * <p>
+ *
* <pre>
* type ::= string
* type ::= int
* </pre>
*/
- @Override
public String readType()
throws IOException {
int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
@@ -3107,12 +3153,11 @@
/**
* Parses the length for an array
- * <p>
+ *
* <pre>
* l b32 b24 b16 b8
* </pre>
*/
- @Override
public int readLength()
throws IOException {
throw new UnsupportedOperationException();
@@ -3120,7 +3165,7 @@
/**
* Parses a 32-bit integer value from the stream.
- * <p>
+ *
* <pre>
* b32 b24 b16 b8
* </pre>
@@ -3152,7 +3197,7 @@
/**
* Parses a 64-bit long value from the stream.
- * <p>
+ *
* <pre>
* b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
@@ -3180,7 +3225,7 @@
/**
* Parses a 64-bit double value from the stream.
- * <p>
+ *
* <pre>
* b64 b56 b48 b40 b32 b24 b16 b8
* </pre>
@@ -3197,6 +3242,38 @@
throw new UnsupportedOperationException();
}
+ private void parseString(StringBuilder sbuf)
+ throws IOException {
+ while (true) {
+ if (_chunkLength <= 0) {
+ if (!parseChunkLength())
+ return;
+ }
+
+ int length = _chunkLength;
+ _chunkLength = 0;
+
+ while (length-- > 0) {
+ sbuf.append((char) parseUTF8Char());
+ }
+ }
+ }
+
+ /**
+ * Reads a character from the underlying stream.
+ */
+ private int parseChar()
+ throws IOException {
+ while (_chunkLength <= 0) {
+ if (!parseChunkLength())
+ return -1;
+ }
+
+ _chunkLength--;
+
+ return parseUTF8Char();
+ }
+
private boolean parseChunkLength()
throws IOException {
if (_isLastChunk)
@@ -3270,21 +3347,6 @@
}
/**
- * Reads a character from the underlying stream.
- */
- private int parseChar()
- throws IOException {
- while (_chunkLength <= 0) {
- if (!parseChunkLength())
- return -1;
- }
-
- _chunkLength--;
-
- return parseUTF8Char();
- }
-
- /**
* Parses a single UTF8 character.
*/
private int parseUTF8Char()
@@ -3375,7 +3437,6 @@
/**
* Reads bytes based on an input stream.
*/
- @Override
public InputStream readInputStream()
throws IOException {
int tag = read();
@@ -3387,7 +3448,7 @@
case BC_BINARY:
case BC_BINARY_CHUNK:
case 'b': //maybe it's a mistype of BC_BINARY_CHUNK
- _isLastChunk = tag == 'B';
+ _isLastChunk = tag == BC_BINARY;
_chunkLength = (read() << 8) + read();
break;
@@ -3410,6 +3471,7 @@
_isLastChunk = true;
_chunkLength = tag - 0x20;
break;
+
case 0x34:
case 0x35:
case 0x36:
@@ -3417,6 +3479,7 @@
_isLastChunk = true;
_chunkLength = (tag - 0x34) * 256 + read();
break;
+
default:
throw expect("binary", tag);
}
@@ -3471,6 +3534,7 @@
_isLastChunk = true;
_chunkLength = code - 0x20;
break;
+
case 0x34:
case 0x35:
case 0x36:
@@ -3478,6 +3542,7 @@
_isLastChunk = true;
_chunkLength = (code - 0x34) * 256 + read();
break;
+
default:
throw expect("byte[]", code);
}
@@ -3518,6 +3583,13 @@
return _buffer[_offset++] & 0xff;
}
+ protected void unread() {
+ if (_offset <= 0)
+ throw new IllegalStateException();
+
+ _offset--;
+ }
+
private final boolean readBuffer()
throws IOException {
byte[] buffer = _buffer;
@@ -3545,7 +3617,6 @@
return true;
}
- @Override
public Reader getReader() {
return null;
}
@@ -3558,16 +3629,21 @@
_offset--;
try {
+ int offset = _offset;
+ String context
+ = buildDebugContext(_buffer, 0, _length, offset);
+
Object obj = readObject();
if (obj != null) {
return error("expected " + expect
+ " at 0x" + Integer.toHexString(ch & 0xff)
- + " " + obj.getClass().getName());
+ + " " + obj.getClass().getName()
+ + "\n " + context + "");
} else
return error("expected " + expect
+ " at 0x" + Integer.toHexString(ch & 0xff) + " null");
- } catch (IOException e) {
+ } catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
return error("expected " + expect
@@ -3576,6 +3652,36 @@
}
}
+ private String buildDebugContext(byte[] buffer, int offset, int length,
+ int errorOffset) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("[");
+ for (int i = 0; i < errorOffset; i++) {
+ int ch = buffer[offset + i];
+ addDebugChar(sb, ch);
+ }
+ sb.append("] ");
+ addDebugChar(sb, buffer[offset + errorOffset]);
+ sb.append(" [");
+ for (int i = errorOffset + 1; i < length; i++) {
+ int ch = buffer[offset + i];
+ addDebugChar(sb, ch);
+ }
+ sb.append("]");
+
+ return sb.toString();
+ }
+
+ private void addDebugChar(StringBuilder sb, int ch) {
+ if (ch >= 0x20 && ch < 0x7f) {
+ sb.append((char) ch);
+ } else if (ch == '\n')
+ sb.append((char) ch);
+ else
+ sb.append(String.format("\\x%02x", ch & 0xff));
+ }
+
protected String codeName(int ch) {
if (ch < 0)
return "end of file";
@@ -3590,6 +3696,10 @@
return new HessianProtocolException(message);
}
+ public void free() {
+ reset();
+ }
+
@Override
public void close()
throws IOException {
@@ -3604,26 +3714,40 @@
final static class ObjectDefinition {
private final String _type;
- private final String[] _fields;
+ private final Deserializer _reader;
+ private final Object[] _fields;
+ private final String[] _fieldNames;
- ObjectDefinition(String type, String[] fields) {
+ ObjectDefinition(String type,
+ Deserializer reader,
+ Object[] fields,
+ String[] fieldNames) {
_type = type;
+ _reader = reader;
_fields = fields;
+ _fieldNames = fieldNames;
}
String getType() {
return _type;
}
- String[] getFieldNames() {
+ Deserializer getReader() {
+ return _reader;
+ }
+
+ Object[] getFields() {
return _fields;
}
+
+ String[] getFieldNames() {
+ return _fieldNames;
+ }
}
class ReadInputStream extends InputStream {
boolean _isClosed = false;
- @Override
public int read()
throws IOException {
if (_isClosed)
@@ -3636,7 +3760,6 @@
return ch;
}
- @Override
public int read(byte[] buffer, int offset, int length)
throws IOException {
if (_isClosed)
@@ -3649,7 +3772,6 @@
return len;
}
- @Override
public void close()
throws IOException {
while (read() >= 0) {
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java
index c4a6850..ed83316 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java
@@ -51,18 +51,19 @@
import com.alibaba.com.caucho.hessian.util.IdentityIntMap;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
/**
* Output stream for Hessian 2 requests.
- * <p>
+ *
* <p>Since HessianOutput does not depend on any classes other than
* in the JDK, it can be extracted independently into a smaller package.
- * <p>
+ *
* <p>HessianOutput is unbuffered, so any client needs to provide
* its own buffering.
- * <p>
+ *
* <pre>
* OutputStream os = ...; // from http connection
* Hessian2Output out = new Hessian2Output(os);
@@ -76,20 +77,35 @@
public class Hessian2Output
extends AbstractHessianOutput
implements Hessian2Constants {
- public final static int SIZE = 4096;
+ // should match Resin buffer size for perf
+ public final static int SIZE = 8 * 1024;
+ // map of references
+ private final IdentityIntMap _refs
+ = new IdentityIntMap(256);
+ // map of classes
+ private final IdentityIntMap _classRefs
+ = new IdentityIntMap(256);
private final byte[] _buffer = new byte[SIZE];
// the output stream/
protected OutputStream _os;
- // map of references
- private IdentityIntMap _refs = new IdentityIntMap();
+ private int _refCount = 0;
private boolean _isCloseStreamOnClose;
- // map of classes
- private HashMap _classRefs;
// map of types
- private HashMap _typeRefs;
+ private HashMap<String, Integer> _typeRefs;
private int _offset;
- private boolean _isStreaming;
+ private boolean _isPacket;
+
+ private boolean _isUnshared;
+
+ /**
+ * Creates a new Hessian output stream, initialized with an
+ * underlying output stream.
+ *
+ * @param os the underlying output stream.
+ */
+ public Hessian2Output() {
+ }
/**
* Creates a new Hessian output stream, initialized with an
@@ -98,7 +114,7 @@
* @param os the underlying output stream.
*/
public Hessian2Output(OutputStream os) {
- _os = os;
+ init(os);
}
@Override
@@ -108,21 +124,10 @@
_os = os;
}
- /**
- * Resets all counters and references
- */
- public void reset() {
+ public void initPacket(OutputStream os) {
resetReferences();
- if (_classRefs != null) {
- _classRefs.clear();
- }
-
- if (_typeRefs != null) {
- _typeRefs.clear();
- }
-
- _offset = 0;
+ _os = os;
}
public boolean isCloseStreamOnClose() {
@@ -134,26 +139,44 @@
}
/**
+ * Sets hessian to be "unshared", meaning it will not detect
+ * duplicate or circular references.
+ */
+ @Override
+ public boolean setUnshared(boolean isUnshared) {
+ boolean oldIsUnshared = _isUnshared;
+
+ _isUnshared = isUnshared;
+
+ return oldIsUnshared;
+ }
+
+ /**
* Writes a complete method call.
*/
@Override
public void call(String method, Object[] args)
throws IOException {
+ writeVersion();
+
int length = args != null ? args.length : 0;
startCall(method, length);
- for (int i = 0; i < args.length; i++)
+ for (int i = 0; i < length; i++) {
writeObject(args[i]);
+ }
completeCall();
+
+ flush();
}
/**
* Starts the method call. Clients would use <code>startCall</code>
* instead of <code>call</code> if they wanted finer control over
* writing the arguments, or needed to write headers.
- * <p>
+ *
* <code><pre>
* C
* string # method name
@@ -168,7 +191,7 @@
int offset = _offset;
if (SIZE < offset + 32) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -183,7 +206,7 @@
/**
* Writes the call tag. This would be followed by the
* method and the arguments
- * <p>
+ *
* <code><pre>
* C
* </pre></code>
@@ -200,7 +223,7 @@
/**
* Starts an envelope.
- * <p>
+ *
* <code><pre>
* E major minor
* m b16 b8 method-name
@@ -213,7 +236,7 @@
int offset = _offset;
if (SIZE < offset + 32) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -224,9 +247,9 @@
/**
* Completes an envelope.
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* Z
* </pre>
@@ -240,14 +263,13 @@
/**
* Writes the method tag.
- * <p>
+ *
* <code><pre>
* string
* </pre></code>
*
* @param method the method name to call.
*/
- @Override
public void writeMethod(String method)
throws IOException {
writeString(method);
@@ -255,7 +277,7 @@
/**
* Completes.
- * <p>
+ *
* <code><pre>
* z
* </pre></code>
@@ -265,16 +287,16 @@
throws IOException {
/*
flushIfFull();
-
+
_buffer[_offset++] = (byte) 'Z';
*/
}
/**
* Starts the reply
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* R
* </pre>
@@ -292,6 +314,7 @@
public void writeVersion()
throws IOException {
flushIfFull();
+
_buffer[_offset++] = (byte) 'H';
_buffer[_offset++] = (byte) 2;
_buffer[_offset++] = (byte) 0;
@@ -299,9 +322,9 @@
/**
* Completes reading the reply
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* z
* </pre>
@@ -313,9 +336,9 @@
/**
* Starts a packet
- * <p>
+ *
* <p>A message contains several objects encapsulated by a length</p>
- * <p>
+ *
* <pre>
* p x02 x00
* </pre>
@@ -331,9 +354,9 @@
/**
* Completes reading the message
- * <p>
+ *
* <p>A successful completion will have a single value:
- * <p>
+ *
* <pre>
* z
* </pre>
@@ -348,19 +371,19 @@
/**
* Writes a fault. The fault will be written
* as a descriptive string followed by an object:
- * <p>
+ *
* <code><pre>
* F map
* </pre></code>
- * <p>
+ *
* <code><pre>
* F H
* \x04code
* \x10the fault code
- * <p>
+ *
* \x07message
* \x11the fault message
- * <p>
+ *
* \x06detail
* M\xnnjavax.ejb.FinderException
* ...
@@ -370,7 +393,6 @@
*
* @param code the fault code, a three digit
*/
- @Override
public void writeFault(String code, String message, Object detail)
throws IOException {
flushIfFull();
@@ -380,7 +402,7 @@
_buffer[_offset++] = (byte) 'F';
_buffer[_offset++] = (byte) 'H';
- _refs.put(new HashMap(), _refs.size());
+ addRef(new Object(), _refCount++, false);
writeString("code");
writeString(code);
@@ -408,7 +430,9 @@
return;
}
- Serializer serializer = findSerializerFactory().getSerializer(object.getClass());
+ Serializer serializer
+ = findSerializerFactory().getObjectSerializer(object.getClass());
+
serializer.writeObject(object, this);
}
@@ -416,7 +440,7 @@
* Writes the list header to the stream. List writers will call
* <code>writeListBegin</code> followed by the list contents and then
* call <code>writeListEnd</code>.
- * <p>
+ *
* <code><pre>
* list ::= V type value* Z
* ::= v type int value*
@@ -424,7 +448,6 @@
*
* @return true for variable lists, false for fixed lists
*/
- @Override
public boolean writeListBegin(int length, String type)
throws IOException {
flushIfFull();
@@ -463,7 +486,6 @@
/**
* Writes the tail of the list to the stream for a variable-length list.
*/
- @Override
public void writeListEnd()
throws IOException {
flushIfFull();
@@ -475,17 +497,16 @@
* Writes the map header to the stream. Map writers will call
* <code>writeMapBegin</code> followed by the map contents and then
* call <code>writeMapEnd</code>.
- * <p>
+ *
* <code><pre>
* map ::= M type (<value> <value>)* Z
* ::= H (<value> <value>)* Z
* </pre></code>
*/
- @Override
public void writeMapBegin(String type)
throws IOException {
if (SIZE < _offset + 32)
- flush();
+ flushBuffer();
if (type != null) {
_buffer[_offset++] = BC_MAP;
@@ -498,18 +519,17 @@
/**
* Writes the tail of the map to the stream.
*/
- @Override
public void writeMapEnd()
throws IOException {
if (SIZE < _offset + 32)
- flush();
+ flushBuffer();
_buffer[_offset++] = (byte) BC_END;
}
/**
* Writes the object definition
- * <p>
+ *
* <code><pre>
* C <string> <int> <string>*
* </pre></code>
@@ -517,16 +537,12 @@
@Override
public int writeObjectBegin(String type)
throws IOException {
- if (_classRefs == null)
- _classRefs = new HashMap();
+ int newRef = _classRefs.size();
+ int ref = _classRefs.put(type, newRef, false);
- Integer refV = (Integer) _classRefs.get(type);
-
- if (refV != null) {
- int ref = refV.intValue();
-
+ if (newRef != ref) {
if (SIZE < _offset + 32)
- flush();
+ flushBuffer();
if (ref <= OBJECT_DIRECT_MAX) {
_buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
@@ -537,12 +553,8 @@
return ref;
} else {
- int ref = _classRefs.size();
-
- _classRefs.put(type, Integer.valueOf(ref));
-
if (SIZE < _offset + 32)
- flush();
+ flushBuffer();
_buffer[_offset++] = (byte) 'C';
@@ -585,7 +597,7 @@
}
if (_typeRefs == null)
- _typeRefs = new HashMap();
+ _typeRefs = new HashMap<String, Integer>();
Integer typeRefV = (Integer) _typeRefs.get(type);
@@ -603,7 +615,7 @@
/**
* Writes a boolean value to the stream. The boolean will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* T
* F
@@ -615,7 +627,7 @@
public void writeBoolean(boolean value)
throws IOException {
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
if (value)
_buffer[_offset++] = (byte) 'T';
@@ -626,7 +638,7 @@
/**
* Writes an integer value to the stream. The integer will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* I b32 b24 b16 b8
* </pre></code>
@@ -640,7 +652,7 @@
byte[] buffer = _buffer;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -667,21 +679,20 @@
/**
* Writes a long value to the stream. The long will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* L b64 b56 b48 b40 b32 b24 b16 b8
* </pre></code>
*
* @param value the long value to write.
*/
- @Override
public void writeLong(long value)
throws IOException {
int offset = _offset;
byte[] buffer = _buffer;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -722,21 +733,20 @@
/**
* Writes a double value to the stream. The double will be written
* with the following syntax:
- * <p>
+ *
* <code><pre>
* D b64 b56 b48 b40 b32 b24 b16 b8
* </pre></code>
*
* @param value the double value to write.
*/
- @Override
public void writeDouble(double value)
throws IOException {
int offset = _offset;
byte[] buffer = _buffer;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -804,7 +814,7 @@
/**
* Writes a date to the stream.
- * <p>
+ *
* <code><pre>
* date ::= d b7 b6 b5 b4 b3 b2 b1 b0
* ::= x65 b3 b2 b1 b0
@@ -812,11 +822,10 @@
*
* @param time the date in milliseconds from the epoch in UTC
*/
- @Override
public void writeUTCDate(long time)
throws IOException {
if (SIZE < _offset + 32)
- flush();
+ flushBuffer();
int offset = _offset;
byte[] buffer = _buffer;
@@ -854,21 +863,20 @@
/**
* Writes a null value to the stream.
* The null will be written with the following syntax
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
*
* @param value the string value to write.
*/
- @Override
public void writeNull()
throws IOException {
int offset = _offset;
byte[] buffer = _buffer;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -880,27 +888,26 @@
/**
* Writes a string value to the stream using UTF-8 encoding.
* The string will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* S b16 b8 string-value
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
*
* @param value the string value to write.
*/
- @Override
public void writeString(String value)
throws IOException {
int offset = _offset;
byte[] buffer = _buffer;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -918,7 +925,7 @@
offset = _offset;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -943,7 +950,7 @@
offset = _offset;
if (SIZE <= offset + 16) {
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -967,25 +974,24 @@
/**
* Writes a string value to the stream using UTF-8 encoding.
* The string will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* S b16 b8 string-value
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
*
* @param value the string value to write.
*/
- @Override
public void writeString(char[] buffer, int offset, int length)
throws IOException {
if (buffer == null) {
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
_buffer[_offset++] = (byte) ('N');
} else {
@@ -993,7 +999,7 @@
int sublen = 0x8000;
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
// chunk can't end in high surrogate
char tail = buffer[offset + sublen - 1];
@@ -1012,7 +1018,7 @@
}
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
if (length <= STRING_DIRECT_MAX) {
_buffer[_offset++] = (byte) (BC_STRING_DIRECT + length);
@@ -1032,25 +1038,24 @@
/**
* Writes a byte array to the stream.
* The array will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* B b16 b18 bytes
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
*
* @param value the string value to write.
*/
- @Override
public void writeBytes(byte[] buffer)
throws IOException {
if (buffer == null) {
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
_buffer[_offset++] = 'N';
} else
@@ -1060,20 +1065,19 @@
/**
* Writes a byte array to the stream.
* The array will be written with the following syntax:
- * <p>
+ *
* <code><pre>
* B b16 b18 bytes
* </pre></code>
* <p>
* If the value is null, it will be written as
- * <p>
+ *
* <code><pre>
* N
* </pre></code>
*
* @param value the string value to write.
*/
- @Override
public void writeBytes(byte[] buffer, int offset, int length)
throws IOException {
if (buffer == null) {
@@ -1082,8 +1086,6 @@
_buffer[_offset++] = (byte) 'N';
} else {
- flush();
-
while (SIZE - _offset - 3 < length) {
int sublen = SIZE - _offset - 3;
@@ -1131,39 +1133,38 @@
/**
* Writes a byte buffer to the stream.
- * <p>
+ *
* <code><pre>
* </pre></code>
*/
- @Override
public void writeByteBufferStart()
throws IOException {
}
/**
* Writes a byte buffer to the stream.
- * <p>
+ *
* <code><pre>
* b b16 b18 bytes
* </pre></code>
*/
- @Override
public void writeByteBufferPart(byte[] buffer, int offset, int length)
throws IOException {
while (length > 0) {
- int sublen = length;
+ flushIfFull();
- if (0x8000 < sublen)
- sublen = 0x8000;
+ int sublen = _buffer.length - _offset;
- flush(); // bypass buffer
+ if (length < sublen)
+ sublen = length;
- _os.write(BC_BINARY_CHUNK);
- _os.write(sublen >> 8);
- _os.write(sublen);
+ _buffer[_offset++] = BC_BINARY_CHUNK;
+ _buffer[_offset++] = (byte) (sublen >> 8);
+ _buffer[_offset++] = (byte) sublen;
- _os.write(buffer, offset, sublen);
+ System.arraycopy(buffer, offset, _buffer, _offset, sublen);
+ _offset += sublen;
length -= sublen;
offset += sublen;
}
@@ -1171,12 +1172,11 @@
/**
* Writes a byte buffer to the stream.
- * <p>
+ *
* <code><pre>
* b b16 b18 bytes
* </pre></code>
*/
- @Override
public void writeByteBufferEnd(byte[] buffer, int offset, int length)
throws IOException {
writeBytes(buffer, offset, length);
@@ -1191,8 +1191,37 @@
}
/**
+ * Writes a full output stream.
+ */
+ @Override
+ public void writeByteStream(InputStream is)
+ throws IOException {
+ while (true) {
+ int len = SIZE - _offset - 3;
+
+ if (len < 16) {
+ flushBuffer();
+ len = SIZE - _offset - 3;
+ }
+
+ len = is.read(_buffer, _offset + 3, len);
+
+ if (len <= 0) {
+ _buffer[_offset++] = BC_BINARY_DIRECT;
+ return;
+ }
+
+ _buffer[_offset + 0] = (byte) BC_BINARY_CHUNK;
+ _buffer[_offset + 1] = (byte) (len >> 8);
+ _buffer[_offset + 2] = (byte) (len);
+
+ _offset += len + 3;
+ }
+ }
+
+ /**
* Writes a reference.
- * <p>
+ *
* <code><pre>
* x51 <int>
* </pre></code>
@@ -1203,7 +1232,7 @@
protected void writeRef(int value)
throws IOException {
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
_buffer[_offset++] = (byte) BC_REF;
@@ -1218,26 +1247,43 @@
@Override
public boolean addRef(Object object)
throws IOException {
- int ref = _refs.get(object);
+ if (_isUnshared) {
+ _refCount++;
+ return false;
+ }
- if (ref >= 0) {
+ int newRef = _refCount;
+
+ int ref = addRef(object, newRef, false);
+
+ if (ref != newRef) {
writeRef(ref);
return true;
} else {
- _refs.put(object, _refs.size());
+ _refCount++;
return false;
}
}
+ @Override
+ public int getRef(Object obj) {
+ if (_isUnshared)
+ return -1;
+
+ return _refs.get(obj);
+ }
+
/**
* Removes a reference.
*/
@Override
public boolean removeRef(Object obj)
throws IOException {
- if (_refs != null) {
+ if (_isUnshared) {
+ return false;
+ } else if (_refs != null) {
_refs.remove(obj);
return true;
@@ -1251,73 +1297,101 @@
@Override
public boolean replaceRef(Object oldRef, Object newRef)
throws IOException {
- Integer value = (Integer) _refs.remove(oldRef);
+ if (_isUnshared) {
+ return false;
+ }
- if (value != null) {
- _refs.put(newRef, value);
+ int value = _refs.get(oldRef);
+
+ if (value >= 0) {
+ addRef(newRef, value, true);
+
+ _refs.remove(oldRef);
+
return true;
} else
return false;
}
- /**
- * Resets the references for streaming.
- */
- @Override
- public void resetReferences() {
- if (_refs != null)
- _refs.clear();
+ private int addRef(Object value, int newRef, boolean isReplace) {
+ int prevRef = _refs.put(value, newRef, isReplace);
+
+ return prevRef;
}
/**
* Starts the streaming message
- * <p>
+ *
* <p>A streaming message starts with 'P'</p>
- * <p>
+ *
* <pre>
* P x02 x00
* </pre>
*/
public void writeStreamingObject(Object obj)
throws IOException {
- startStreamingPacket();
+ startPacket();
writeObject(obj);
- endStreamingPacket();
+ endPacket();
}
/**
* Starts a streaming packet
- * <p>
- * <p>A streaming message starts with 'P'</p>
- * <p>
- * <pre>
- * P x02 x00
- * </pre>
+ *
+ * <p>A streaming contains a set of chunks, ending with a zero chunk.
+ * Each chunk is a length followed by data where the length is
+ * encoded by (b1xxxxxxxx)* b0xxxxxxxx</p>
*/
- public void startStreamingPacket()
+ public void startPacket()
throws IOException {
- if (_refs != null)
+ if (_refs != null) {
_refs.clear();
+ _refCount = 0;
+ }
- flush();
+ flushBuffer();
- _isStreaming = true;
- _offset = 3;
+ _isPacket = true;
+ _offset = 4;
+ _buffer[0] = (byte) 0x05; // 0x05 = binary
+ _buffer[1] = (byte) 0x55;
+ _buffer[2] = (byte) 0x55;
+ _buffer[3] = (byte) 0x55;
}
- public void endStreamingPacket()
+ public void endPacket()
throws IOException {
- int len = _offset - 3;
+ int offset = _offset;
- _buffer[0] = (byte) 'P';
- _buffer[1] = (byte) (len >> 8);
- _buffer[2] = (byte) len;
+ OutputStream os = _os;
- _isStreaming = false;
+ if (os == null) {
+ _offset = 0;
+ return;
+ }
- flush();
+ int len = offset - 4;
+
+ if (len < 0x7e) {
+ _buffer[2] = _buffer[0];
+ _buffer[3] = (byte) (len);
+ } else {
+ _buffer[1] = (byte) (0x7e);
+ _buffer[2] = (byte) (len >> 8);
+ _buffer[3] = (byte) (len);
+ }
+
+ _isPacket = false;
+ _offset = 0;
+
+ if (os == null) {
+ } else if (len < 0x7e) {
+ os.write(_buffer, 2, offset - 2);
+ } else {
+ os.write(_buffer, 0, offset);
+ }
}
/**
@@ -1328,7 +1402,7 @@
public void printLenString(String v)
throws IOException {
if (SIZE < _offset + 16)
- flush();
+ flushBuffer();
if (v == null) {
_buffer[_offset++] = (byte) (0);
@@ -1365,7 +1439,7 @@
for (int i = 0; i < length; i++) {
if (SIZE <= offset + 16) {
_offset = offset;
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -1399,7 +1473,7 @@
for (int i = 0; i < length; i++) {
if (SIZE <= offset + 16) {
_offset = offset;
- flush();
+ flushBuffer();
offset = _offset;
}
@@ -1425,12 +1499,10 @@
int offset = _offset;
if (SIZE < offset + 32) {
- _offset = 0;
- _os.write(_buffer, 0, offset);
+ flushBuffer();
}
}
- @Override
public final void flush()
throws IOException {
flushBuffer();
@@ -1443,23 +1515,33 @@
throws IOException {
int offset = _offset;
- if (!_isStreaming && offset > 0) {
+ OutputStream os = _os;
+
+ if (!_isPacket && offset > 0) {
_offset = 0;
+ if (os != null)
+ os.write(_buffer, 0, offset);
+ } else if (_isPacket && offset > 4) {
+ int len = offset - 4;
- _os.write(_buffer, 0, offset);
- } else if (_isStreaming && offset > 3) {
- int len = offset - 3;
- _buffer[0] = 'p';
- _buffer[1] = (byte) (len >> 8);
- _buffer[2] = (byte) len;
- _offset = 3;
+ _buffer[0] |= (byte) 0x80;
+ _buffer[1] = (byte) (0x7e);
+ _buffer[2] = (byte) (len >> 8);
+ _buffer[3] = (byte) (len);
+ _offset = 4;
- _os.write(_buffer, 0, offset);
+ if (os != null)
+ os.write(_buffer, 0, offset);
+
+ _buffer[0] = (byte) 0x00;
+ _buffer[1] = (byte) 0x56;
+ _buffer[2] = (byte) 0x56;
+ _buffer[3] = (byte) 0x56;
}
}
@Override
- public final void close()
+ public void close()
throws IOException {
// hessian/3a8c
flush();
@@ -1473,13 +1555,47 @@
}
}
+ public void free() {
+ reset();
+
+ _os = null;
+ _isCloseStreamOnClose = false;
+ }
+
+ /**
+ * Resets the references for streaming.
+ */
+ @Override
+ public void resetReferences() {
+ if (_refs != null) {
+ _refs.clear();
+ _refCount = 0;
+ }
+ }
+
+ /**
+ * Resets all counters and references
+ */
+ public void reset() {
+ if (_refs != null) {
+ _refs.clear();
+ _refCount = 0;
+ }
+
+ _classRefs.clear();
+ _typeRefs = null;
+ _offset = 0;
+ _isPacket = false;
+ _isUnshared = false;
+ }
+
class BytesOutputStream extends OutputStream {
private int _startOffset;
BytesOutputStream()
throws IOException {
if (SIZE < _offset + 16) {
- Hessian2Output.this.flush();
+ Hessian2Output.this.flushBuffer();
}
_startOffset = _offset;
@@ -1496,7 +1612,7 @@
_buffer[_startOffset + 1] = (byte) (length >> 8);
_buffer[_startOffset + 2] = (byte) (length);
- Hessian2Output.this.flush();
+ Hessian2Output.this.flushBuffer();
_startOffset = _offset;
_offset += 3;
@@ -1529,7 +1645,7 @@
_buffer[_startOffset + 1] = (byte) (chunkLength >> 8);
_buffer[_startOffset + 2] = (byte) (chunkLength);
- Hessian2Output.this.flush();
+ Hessian2Output.this.flushBuffer();
_startOffset = _offset;
_offset += 3;
@@ -1552,7 +1668,7 @@
_buffer[startOffset + 1] = (byte) (length >> 8);
_buffer[startOffset + 2] = (byte) (length);
- Hessian2Output.this.flush();
+ Hessian2Output.this.flushBuffer();
}
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java
index ebf8b77..c986297 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingInput.java
@@ -50,11 +50,24 @@
import java.io.IOException;
import java.io.InputStream;
+import java.util.logging.Level;
+import java.util.logging.Logger;
/**
- * Output stream for Hessian 2 streaming requests.
+ * Input stream for Hessian 2 streaming requests using WebSocket.
+ * <p>
+ * For best performance, use HessianFactory:
+ *
+ * <code><pre>
+ * HessianFactory factory = new HessianFactory();
+ * Hessian2StreamingInput hIn = factory.createHessian2StreamingInput(is);
+ * </pre></code>
*/
public class Hessian2StreamingInput {
+ private static final Logger log
+ = Logger.getLogger(Hessian2StreamingInput.class.getName());
+
+ private StreamingInputStream _is;
private Hessian2Input _in;
/**
@@ -64,7 +77,38 @@
* @param is the underlying output stream.
*/
public Hessian2StreamingInput(InputStream is) {
- _in = new Hessian2Input(new StreamingInputStream(is));
+ _is = new StreamingInputStream(is);
+ _in = new Hessian2Input(_is);
+ }
+
+ public void setSerializerFactory(SerializerFactory factory) {
+ _in.setSerializerFactory(factory);
+ }
+
+ public boolean isDataAvailable() {
+ StreamingInputStream is = _is;
+
+ return is != null && is.isDataAvailable();
+ }
+
+ public Hessian2Input startPacket()
+ throws IOException {
+ if (_is.startPacket()) {
+ _in.resetReferences();
+ _in.resetBuffer(); // XXX:
+ return _in;
+ } else
+ return null;
+ }
+
+ public void endPacket()
+ throws IOException {
+ _is.endPacket();
+ _in.resetBuffer(); // XXX:
+ }
+
+ public Hessian2Input getHessianInput() {
+ return _in;
}
/**
@@ -72,7 +116,13 @@
*/
public Object readObject()
throws IOException {
- return _in.readStreamingObject();
+ _is.startPacket();
+
+ Object obj = _in.readStreamingObject();
+
+ _is.endPacket();
+
+ return obj;
}
/**
@@ -85,36 +135,68 @@
static class StreamingInputStream extends InputStream {
private InputStream _is;
+
private int _length;
+ private boolean _isPacketEnd;
StreamingInputStream(InputStream is) {
_is = is;
}
- @Override
+ public boolean isDataAvailable() {
+ try {
+ return _is != null && _is.available() > 0;
+ } catch (IOException e) {
+ log.log(Level.FINER, e.toString(), e);
+
+ return true;
+ }
+ }
+
+ public boolean startPacket()
+ throws IOException {
+ // skip zero-length packets
+ do {
+ _isPacketEnd = false;
+ } while ((_length = readChunkLength(_is)) == 0);
+
+ return _length > 0;
+ }
+
+ public void endPacket()
+ throws IOException {
+ while (!_isPacketEnd) {
+ if (_length <= 0)
+ _length = readChunkLength(_is);
+
+ if (_length > 0) {
+ _is.skip(_length);
+ _length = 0;
+ }
+ }
+
+ if (_length > 0) {
+ _is.skip(_length);
+ _length = 0;
+ }
+ }
+
public int read()
throws IOException {
InputStream is = _is;
- while (_length == 0) {
- int code = is.read();
-
- if (code < 0)
- return -1;
- else if (code != 'p' && code != 'P')
- throw new HessianProtocolException("expected streaming packet at 0x"
- + Integer.toHexString(code & 0xff));
-
- int d1 = is.read();
- int d2 = is.read();
-
- if (d2 < 0)
+ if (_length == 0) {
+ if (_isPacketEnd)
return -1;
- _length = (d1 << 8) + d2;
+ _length = readChunkLength(is);
+
+ if (_length <= 0)
+ return -1;
}
_length--;
+
return is.read();
}
@@ -123,24 +205,14 @@
throws IOException {
InputStream is = _is;
- while (_length == 0) {
- int code = is.read();
-
- if (code < 0)
- return -1;
- else if (code != 'p' && code != 'P') {
- throw new HessianProtocolException("expected streaming packet at 0x"
- + Integer.toHexString(code & 0xff)
- + " (" + (char) code + ")");
- }
-
- int d1 = is.read();
- int d2 = is.read();
-
- if (d2 < 0)
+ if (_length <= 0) {
+ if (_isPacketEnd)
return -1;
- _length = (d1 << 8) + d2;
+ _length = readChunkLength(is);
+
+ if (_length <= 0)
+ return -1;
}
int sublen = _length;
@@ -156,5 +228,42 @@
return sublen;
}
+
+ private int readChunkLength(InputStream is)
+ throws IOException {
+ if (_isPacketEnd)
+ return -1;
+
+ int length = 0;
+
+ int code = is.read();
+
+ if (code < 0) {
+ _isPacketEnd = true;
+ return -1;
+ }
+
+ _isPacketEnd = (code & 0x80) == 0;
+
+ int len = is.read() & 0x7f;
+
+ if (len < 0x7e) {
+ length = len;
+ } else if (len == 0x7e) {
+ length = (((is.read() & 0xff) << 8)
+ + (is.read() & 0xff));
+ } else {
+ length = (((is.read() & 0xff) << 56)
+ + ((is.read() & 0xff) << 48)
+ + ((is.read() & 0xff) << 40)
+ + ((is.read() & 0xff) << 32)
+ + ((is.read() & 0xff) << 24)
+ + ((is.read() & 0xff) << 16)
+ + ((is.read() & 0xff) << 8)
+ + ((is.read() & 0xff)));
+ }
+
+ return length;
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java
index 19fb331..97514c3 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2StreamingOutput.java
@@ -67,6 +67,14 @@
_out = new Hessian2Output(os);
}
+ public Hessian2StreamingOutput(Hessian2Output out) {
+ _out = out;
+ }
+
+ public Hessian2Output getHessian2Output() {
+ return _out;
+ }
+
public boolean isCloseStreamOnClose() {
return _out.isCloseStreamOnClose();
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianFactory.java
new file mode 100644
index 0000000..64a2883
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianFactory.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import com.alibaba.com.caucho.hessian.util.HessianFreeList;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.logging.Logger;
+
+/**
+ * Factory for creating HessianInput and HessianOutput streams.
+ */
+public class HessianFactory {
+ public static final Logger log
+ = Logger.getLogger(HessianFactory.class.getName());
+ private final HessianFreeList<Hessian2Output> _freeHessian2Output
+ = new HessianFreeList<Hessian2Output>(32);
+ private final HessianFreeList<Hessian2Input> _freeHessian2Input
+ = new HessianFreeList<Hessian2Input>(32);
+ private SerializerFactory _serializerFactory;
+ private SerializerFactory _defaultSerializerFactory;
+
+ public HessianFactory() {
+ _defaultSerializerFactory = SerializerFactory.createDefault();
+ _serializerFactory = _defaultSerializerFactory;
+ }
+
+ public SerializerFactory getSerializerFactory() {
+ // the default serializer factory cannot be modified by external
+ // callers
+ if (_serializerFactory == _defaultSerializerFactory) {
+ _serializerFactory = new SerializerFactory();
+ }
+
+ return _serializerFactory;
+ }
+
+ public void setSerializerFactory(SerializerFactory factory) {
+ _serializerFactory = factory;
+ }
+
+ /**
+ * Enable whitelist deserialization mode. Only classes matching the whitelist
+ * will be allowed.
+ */
+ public void setWhitelist(boolean isWhitelist) {
+ getSerializerFactory().getClassFactory().setWhitelist(isWhitelist);
+ }
+
+ /**
+ * Allow a class or package based on a pattern.
+ * <p>
+ * Examples: "java.util.*", "com.foo.io.Bean"
+ */
+ public void allow(String pattern) {
+ getSerializerFactory().getClassFactory().allow(pattern);
+ }
+
+
+ /**
+ * Deny a class or package based on a pattern.
+ * <p>
+ * Examples: "java.util.*", "com.foo.io.Bean"
+ */
+ public void deny(String pattern) {
+ getSerializerFactory().getClassFactory().deny(pattern);
+ }
+
+ /**
+ * Creates a new Hessian 2.0 deserializer.
+ */
+ public Hessian2Input createHessian2Input(InputStream is) {
+ Hessian2Input in = _freeHessian2Input.allocate();
+
+ if (in == null) {
+ in = new Hessian2Input(is);
+ in.setSerializerFactory(getSerializerFactory());
+ } else {
+ in.init(is);
+ }
+
+ return in;
+ }
+
+ /**
+ * Frees a Hessian 2.0 deserializer
+ */
+ public void freeHessian2Input(Hessian2Input in) {
+ if (in == null)
+ return;
+
+ in.free();
+
+ _freeHessian2Input.free(in);
+ }
+
+ /**
+ * Creates a new Hessian 2.0 deserializer.
+ */
+ public Hessian2StreamingInput createHessian2StreamingInput(InputStream is) {
+ Hessian2StreamingInput in = new Hessian2StreamingInput(is);
+ in.setSerializerFactory(getSerializerFactory());
+
+ return in;
+ }
+
+ /**
+ * Frees a Hessian 2.0 deserializer
+ */
+ public void freeHessian2StreamingInput(Hessian2StreamingInput in) {
+ }
+
+ /**
+ * Creates a new Hessian 2.0 serializer.
+ */
+ public Hessian2Output createHessian2Output(OutputStream os) {
+ Hessian2Output out = createHessian2Output();
+
+ out.init(os);
+
+ return out;
+ }
+
+ /**
+ * Creates a new Hessian 2.0 serializer.
+ */
+ public Hessian2Output createHessian2Output() {
+ Hessian2Output out = _freeHessian2Output.allocate();
+
+ if (out == null) {
+ out = new Hessian2Output();
+
+ out.setSerializerFactory(getSerializerFactory());
+ }
+
+ return out;
+ }
+
+ /**
+ * Frees a Hessian 2.0 serializer
+ */
+ public void freeHessian2Output(Hessian2Output out) {
+ if (out == null)
+ return;
+
+ out.free();
+
+ _freeHessian2Output.free(out);
+ }
+
+ /**
+ * Creates a new Hessian 2.0 serializer.
+ */
+ public Hessian2StreamingOutput createHessian2StreamingOutput(OutputStream os) {
+ Hessian2Output out = createHessian2Output(os);
+
+ return new Hessian2StreamingOutput(out);
+ }
+
+ /**
+ * Frees a Hessian 2.0 serializer
+ */
+ public void freeHessian2StreamingOutput(Hessian2StreamingOutput out) {
+ if (out == null)
+ return;
+
+ freeHessian2Output(out.getHessian2Output());
+ }
+
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianMethodSerializationException.java
similarity index 70%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/HessianMethodSerializationException.java
index 72a9822..9419242 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianMethodSerializationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -48,18 +48,37 @@
package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
+import com.alibaba.com.caucho.hessian.HessianException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Exception for faults when the fault doesn't return a java exception.
+ * This exception is required for MicroHessianInput.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class HessianMethodSerializationException extends HessianException {
/**
- * Looks up a proxy object.
+ * Zero-arg constructor.
*/
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public HessianMethodSerializationException() {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianMethodSerializationException(String message) {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianMethodSerializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianMethodSerializationException(Throwable cause) {
+ super(cause);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java
index 28aa320..6456c1c 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianProtocolException.java
@@ -98,7 +98,6 @@
/**
* Returns the underlying cause.
*/
- @Override
public Throwable getCause() {
return getRootCause();
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java
index 0f5755e..c3def9d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/HessianRemote.java
@@ -52,7 +52,7 @@
* Encapsulates a remote address when no stub is available, e.g. for
* Java MicroEdition.
*/
-public class HessianRemote {
+public class HessianRemote implements java.io.Serializable {
private String type;
private String url;
@@ -97,7 +97,6 @@
/**
* Defines the hashcode.
*/
- @Override
public int hashCode() {
return url.hashCode();
}
@@ -105,7 +104,6 @@
/**
* Defines equality
*/
- @Override
public boolean equals(Object obj) {
if (!(obj instanceof HessianRemote))
return false;
@@ -118,8 +116,7 @@
/**
* Readable version of the remote.
*/
- @Override
public String toString() {
- return "[HessianRemote " + url + "]";
+ return "HessianRemote[" + url + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java b/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java
index 261d4be..9b66c80 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/IOExceptionWrapper.java
@@ -68,7 +68,6 @@
_cause = cause;
}
- @Override
public Throwable getCause() {
return _cause;
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/InetAddressHandle.java
similarity index 74%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/InetAddressHandle.java
index be505fb..dad139a 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/InetAddressHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -48,9 +48,31 @@
package com.alibaba.com.caucho.hessian.io;
+import java.net.InetAddress;
+import java.util.logging.Level;
import java.util.logging.Logger;
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Handle for an InetAddress object.
+ */
+public class InetAddressHandle implements java.io.Serializable, HessianHandle {
+ private static final Logger log = Logger.getLogger(InetAddressHandle.class.getName());
+
+ private String hostName;
+ private byte[] address;
+
+ public InetAddressHandle(String hostName, byte[] address) {
+ this.hostName = hostName;
+ this.address = address;
+ }
+
+ private Object readResolve() {
+ try {
+ return InetAddress.getByAddress(this.hostName, this.address);
+ } catch (Exception e) {
+ log.log(Level.FINE, e.toString(), e);
+
+ return null;
+ }
+ }
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/InetAddressSerializer.java
similarity index 79%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/InetAddressSerializer.java
index 72a9822..c0785a6 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/InetAddressSerializer.java
@@ -49,17 +49,27 @@
package com.alibaba.com.caucho.hessian.io;
import java.io.IOException;
+import java.net.InetAddress;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a locale.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class InetAddressSerializer extends AbstractSerializer {
+ private static InetAddressSerializer SERIALIZER = new InetAddressSerializer();
+
+ public static InetAddressSerializer create() {
+ return SERIALIZER;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ InetAddress addr = (InetAddress) obj;
+ out.writeObject(new InetAddressHandle(addr.getHostName(),
+ addr.getAddress()));
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java
index 2dd0290..cbe92bf 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java
@@ -54,10 +54,12 @@
* Serializing a stream object.
*/
public class InputStreamDeserializer extends AbstractDeserializer {
+ public static final InputStreamDeserializer DESER
+ = new InputStreamDeserializer();
+
public InputStreamDeserializer() {
}
- @Override
public Object readObject(AbstractHessianInput in)
throws IOException {
return in.readInputStream();
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java
index 9bf87e6..ecb5165 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamSerializer.java
@@ -58,7 +58,6 @@
public InputStreamSerializer() {
}
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
InputStream is = (InputStream) obj;
@@ -66,14 +65,7 @@
if (is == null)
out.writeNull();
else {
- byte[] buf = new byte[1024];
- int len;
-
- while ((len = is.read(buf, 0, buf.length)) > 0) {
- out.writeByteBufferPart(buf, 0, len);
- }
-
- out.writeByteBufferEnd(buf, 0, 0);
+ out.writeByteStream(is);
}
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorDeserializer.java
similarity index 78%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/IteratorDeserializer.java
index 72a9822..5a8a209 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorDeserializer.java
@@ -49,17 +49,35 @@
package com.alibaba.com.caucho.hessian.io;
import java.io.IOException;
+import java.util.ArrayList;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing a JDK 1.2 Collection.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class IteratorDeserializer extends AbstractListDeserializer {
+ private static IteratorDeserializer _deserializer;
+
+ public static IteratorDeserializer create() {
+ if (_deserializer == null)
+ _deserializer = new IteratorDeserializer();
+
+ return _deserializer;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public Object readList(AbstractHessianInput in, int length)
throws IOException {
- return new HessianRemote(type, url);
+ ArrayList list = new ArrayList();
+
+ in.addRef(list);
+
+ while (!in.isEnd())
+ list.add(in.readObject());
+
+ in.readEnd();
+
+ return list.iterator();
}
}
+
+
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java
index 2d704d2..e09f0c9 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/IteratorSerializer.java
@@ -64,7 +64,6 @@
return _serializer;
}
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
Iterator iter = (Iterator) obj;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
index f20b31d..e9e16bf 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/JavaDeserializer.java
@@ -48,36 +48,29 @@
package com.alibaba.com.caucho.hessian.io;
+import com.alibaba.com.caucho.hessian.io.FieldDeserializer2Factory.NullFieldDeserializer;
+
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Logger;
/**
* Serializing an object for known object types.
*/
public class JavaDeserializer extends AbstractMapDeserializer {
- private static final Logger log
- = Logger.getLogger(JavaDeserializer.class.getName());
-
- private Class _type;
- private HashMap _fieldMap;
+ private Class<?> _type;
+ private HashMap<?, FieldDeserializer2> _fieldMap;
private Method _readResolve;
- private Constructor _constructor;
+ private Constructor<?> _constructor;
private Object[] _constructorArgs;
- public JavaDeserializer(Class cl) {
+ public JavaDeserializer(Class<?> cl, FieldDeserializer2Factory fieldFactory) {
_type = cl;
- _fieldMap = getFieldMap(cl);
+ _fieldMap = getFieldMap(cl, fieldFactory);
_readResolve = getReadResolve(cl);
@@ -85,55 +78,14 @@
_readResolve.setAccessible(true);
}
- Constructor[] constructors = cl.getDeclaredConstructors();
- long bestCost = Long.MAX_VALUE;
-
- for (int i = 0; i < constructors.length; i++) {
- Class[] param = constructors[i].getParameterTypes();
- long cost = 0;
-
- for (int j = 0; j < param.length; j++) {
- cost = 4 * cost;
-
- if (Object.class.equals(param[j]))
- cost += 1;
- else if (String.class.equals(param[j]))
- cost += 2;
- else if (int.class.equals(param[j]))
- cost += 3;
- else if (long.class.equals(param[j]))
- cost += 4;
- else if (param[j].isPrimitive())
- cost += 5;
- else
- cost += 6;
- }
-
- if (cost < 0 || cost > (1 << 48))
- cost = 1 << 48;
-
- cost += (long) param.length << 48;
-
- if (cost < bestCost) {
- _constructor = constructors[i];
- bestCost = cost;
- }
- }
-
- if (_constructor != null) {
- _constructor.setAccessible(true);
- Class[] params = _constructor.getParameterTypes();
- _constructorArgs = new Object[params.length];
- for (int i = 0; i < params.length; i++) {
- _constructorArgs[i] = getParamArg(params[i]);
- }
- }
+ _constructor = getConstructor(cl);
+ _constructorArgs = getConstructorArgs(_constructor);
}
/**
* Creates a map of the classes fields.
*/
- protected static Object getParamArg(Class cl) {
+ protected static Object getParamArg(Class<?> cl) {
if (!cl.isPrimitive())
return null;
else if (boolean.class.equals(cl))
@@ -174,12 +126,75 @@
throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
}
+ protected Constructor<?> getConstructor(Class<?> cl) {
+ Constructor<?>[] constructors = cl.getDeclaredConstructors();
+ long bestCost = Long.MAX_VALUE;
+
+ Constructor<?> constructor = null;
+
+ for (int i = 0; i < constructors.length; i++) {
+ Class<?>[] param = constructors[i].getParameterTypes();
+ long cost = 0;
+
+ for (int j = 0; j < param.length; j++) {
+ cost = 4 * cost;
+
+ if (Object.class.equals(param[j]))
+ cost += 1;
+ else if (String.class.equals(param[j]))
+ cost += 2;
+ else if (int.class.equals(param[j]))
+ cost += 3;
+ else if (long.class.equals(param[j]))
+ cost += 4;
+ else if (param[j].isPrimitive())
+ cost += 5;
+ else
+ cost += 6;
+ }
+
+ if (cost < 0 || cost > (1 << 48))
+ cost = 1 << 48;
+
+ cost += (long) param.length << 48;
+
+ if (cost < bestCost) {
+ constructor = constructors[i];
+ bestCost = cost;
+ }
+ }
+
+ if (constructor != null) {
+ constructor.setAccessible(true);
+ }
+
+ return constructor;
+ }
+
+ protected Object[] getConstructorArgs(Constructor<?> constructor) {
+ Object[] constructorArgs = null;
+
+ if (constructor != null) {
+ Class<?>[] params = constructor.getParameterTypes();
+ constructorArgs = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ constructorArgs[i] = getParamArg(params[i]);
+ }
+ }
+
+ return constructorArgs;
+ }
+
@Override
- public Class getType() {
+ public Class<?> getType() {
return _type;
}
@Override
+ public boolean isReadResolve() {
+ return _readResolve != null;
+ }
+
public Object readMap(AbstractHessianInput in)
throws IOException {
try {
@@ -196,7 +211,40 @@
}
@Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object[] createFields(int len) {
+ return new FieldDeserializer2[len];
+ }
+
+ @Override
+ public Object createField(String name) {
+ Object reader = _fieldMap.get(name);
+
+ if (reader == null)
+ reader = NullFieldDeserializer.DESER;
+
+ return reader;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readObject(in, obj, (FieldDeserializer2[]) fields);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ String[] fieldNames)
throws IOException {
try {
Object obj = instantiate();
@@ -214,15 +262,15 @@
/**
* Returns the readResolve method
*/
- protected Method getReadResolve(Class cl) {
+ protected Method getReadResolve(Class<?> cl) {
for (; cl != null; cl = cl.getSuperclass()) {
Method[] methods = cl.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
- if (method.getName().equals("readResolve") &&
- method.getParameterTypes().length == 0)
+ if (method.getName().equals("readResolve")
+ && method.getParameterTypes().length == 0)
return method;
}
}
@@ -238,7 +286,7 @@
while (!in.isEnd()) {
Object key = in.readObject();
- FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(key);
+ FieldDeserializer2 deser = _fieldMap.get(key);
if (deser != null)
deser.deserialize(in, obj);
@@ -248,7 +296,7 @@
in.readMapEnd();
- Object resolve = resolve(obj);
+ Object resolve = resolve(in, obj);
if (obj != resolve)
in.setRef(ref, resolve);
@@ -261,25 +309,18 @@
}
}
- public Object readObject(AbstractHessianInput in,
- Object obj,
- String[] fieldNames)
+ private Object readObject(AbstractHessianInput in,
+ Object obj,
+ FieldDeserializer2[] fields)
throws IOException {
try {
int ref = in.addRef(obj);
- for (int i = 0; i < fieldNames.length; i++) {
- String name = fieldNames[i];
-
- FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(name);
-
- if (deser != null)
- deser.deserialize(in, obj);
- else
- in.readObject();
+ for (FieldDeserializer2 reader : fields) {
+ reader.deserialize(in, obj);
}
- Object resolve = resolve(obj);
+ Object resolve = resolve(in, obj);
if (obj != resolve)
in.setRef(ref, resolve);
@@ -292,14 +333,45 @@
}
}
- private Object resolve(Object obj)
+ public Object readObject(AbstractHessianInput in,
+ Object obj,
+ String[] fieldNames)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ for (String fieldName : fieldNames) {
+ FieldDeserializer2 reader = _fieldMap.get(fieldName);
+
+ if (reader != null)
+ reader.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ Object resolve = resolve(in, obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
+ }
+ }
+
+ protected Object resolve(AbstractHessianInput in, Object obj)
throws Exception {
// if there's a readResolve method, call it
try {
if (_readResolve != null)
return _readResolve.invoke(obj, new Object[0]);
} catch (InvocationTargetException e) {
- if (e.getTargetException() != null)
+ if (e.getCause() instanceof Exception)
+ throw (Exception) e.getCause();
+ else
throw e;
}
@@ -321,8 +393,10 @@
/**
* Creates a map of the classes fields.
*/
- protected HashMap getFieldMap(Class cl) {
- HashMap fieldMap = new HashMap();
+ protected HashMap<String, FieldDeserializer2>
+ getFieldMap(Class<?> cl, FieldDeserializer2Factory fieldFactory) {
+ HashMap<String, FieldDeserializer2> fieldMap
+ = new HashMap<String, FieldDeserializer2>();
for (; cl != null; cl = cl.getSuperclass()) {
Field[] fields = cl.getDeclaredFields();
@@ -335,53 +409,16 @@
else if (fieldMap.get(field.getName()) != null)
continue;
- // XXX: could parameterize the handler to only deal with public
- try {
- field.setAccessible(true);
- } catch (Throwable e) {
- e.printStackTrace();
- }
+ /*
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ field.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ */
- Class type = field.getType();
- FieldDeserializer deser;
-
- if (String.class.equals(type))
- deser = new StringFieldDeserializer(field);
- else if (byte.class.equals(type)) {
- deser = new ByteFieldDeserializer(field);
- } else if (short.class.equals(type)) {
- deser = new ShortFieldDeserializer(field);
- } else if (int.class.equals(type)) {
- deser = new IntFieldDeserializer(field);
- } else if (long.class.equals(type)) {
- deser = new LongFieldDeserializer(field);
- } else if (float.class.equals(type)) {
- deser = new FloatFieldDeserializer(field);
- } else if (double.class.equals(type)) {
- deser = new DoubleFieldDeserializer(field);
- } else if (boolean.class.equals(type)) {
- deser = new BooleanFieldDeserializer(field);
- } else if (java.sql.Date.class.equals(type)) {
- deser = new SqlDateFieldDeserializer(field);
- } else if (java.sql.Timestamp.class.equals(type)) {
- deser = new SqlTimestampFieldDeserializer(field);
- } else if (java.sql.Time.class.equals(type)) {
- deser = new SqlTimeFieldDeserializer(field);
- }
- // support generic type of map
- else if (Map.class.equals(type)
- && field.getGenericType() != field.getType()) {
- deser = new ObjectMapFieldDeserializer(field);
- } else if (List.class.equals(type)
- && field.getGenericType() != field.getType()) {
- deser = new ObjectListFieldDeserializer(field);
- } else if (Set.class.equals(type)
- && field.getGenericType() != field.getType()) {
- deser = new ObjectSetFieldDeserializer(field);
- }
- else {
- deser = new ObjectFieldDeserializer(field);
- }
+ FieldDeserializer2 deser = fieldFactory.create(field);
fieldMap.put(field.getName(), deser);
}
@@ -389,398 +426,4 @@
return fieldMap;
}
-
- abstract static class FieldDeserializer {
- abstract void deserialize(AbstractHessianInput in, Object obj)
- throws IOException;
- }
-
- static class ObjectFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- ObjectFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- Object value = null;
-
- try {
- value = in.readObject(_field.getType());
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class BooleanFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- BooleanFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- boolean value = false;
-
- try {
- value = in.readBoolean();
-
- _field.setBoolean(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class ByteFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- ByteFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- int value = 0;
-
- try {
- value = in.readInt();
-
- _field.setByte(obj, (byte) value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class ShortFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- ShortFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- int value = 0;
-
- try {
- value = in.readInt();
-
- _field.setShort(obj, (short) value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class ObjectMapFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- ObjectMapFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- Object value = null;
-
- try {
-
- Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
- value = in.readObject(_field.getType(),
- isPrimitive(types[0]) ? (Class<?>) types[0] : null,
- isPrimitive(types[1]) ? (Class<?>) types[1] : null
- );
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class ObjectListFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- ObjectListFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- Object value = null;
-
- try {
-
- Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
- value = in.readObject(_field.getType(),
- isPrimitive(types[0]) ? (Class<?>) types[0] : null
- );
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class ObjectSetFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- ObjectSetFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- Object value = null;
-
- try {
-
- Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
- value = in.readObject(_field.getType(),
- isPrimitive(types[0]) ? (Class<?>) types[0] : null
- );
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
-
- static class IntFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- IntFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- int value = 0;
-
- try {
- value = in.readInt();
-
- _field.setInt(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class LongFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- LongFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- long value = 0;
-
- try {
- value = in.readLong();
-
- _field.setLong(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class FloatFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- FloatFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- double value = 0;
-
- try {
- value = in.readDouble();
-
- _field.setFloat(obj, (float) value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class DoubleFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- DoubleFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- double value = 0;
-
- try {
- value = in.readDouble();
-
- _field.setDouble(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class StringFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- StringFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- String value = null;
-
- try {
- value = in.readString();
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class SqlDateFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- SqlDateFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- java.sql.Date value = null;
-
- try {
- java.util.Date date = (java.util.Date) in.readObject();
- if (date != null)
- value = new java.sql.Date(date.getTime());
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class SqlTimestampFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- SqlTimestampFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- java.sql.Timestamp value = null;
-
- try {
- java.util.Date date = (java.util.Date) in.readObject();
- if (date != null)
- value = new java.sql.Timestamp(date.getTime());
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- static class SqlTimeFieldDeserializer extends FieldDeserializer {
- private final Field _field;
-
- SqlTimeFieldDeserializer(Field field) {
- _field = field;
- }
-
- @Override
- void deserialize(AbstractHessianInput in, Object obj)
- throws IOException {
- java.sql.Time value = null;
-
- try {
- java.util.Date date = (java.util.Date) in.readObject();
- if (date != null) value = new java.sql.Time(date.getTime());
-
- _field.set(obj, value);
- } catch (Exception e) {
- logDeserializeError(_field, obj, value, e);
- }
- }
- }
-
- /**
- * @see java.lang.Boolean#TYPE
- * @see java.lang.Character#TYPE
- * @see java.lang.Byte#TYPE
- * @see java.lang.Short#TYPE
- * @see java.lang.Integer#TYPE
- * @see java.lang.Long#TYPE
- * @see java.lang.Float#TYPE
- * @see java.lang.Double#TYPE
- * @see java.lang.Void#TYPE
- */
- private static boolean isPrimitive(Type type) {
- try {
- if (type != null) {
- if (type instanceof Class<?>) {
- Class<?> clazz = (Class<?>) type;
- return clazz.isPrimitive()
- || PRIMITIVE_TYPE.containsKey(clazz.getName());
- }
- }
- } catch (Exception e) {
- // ignore exception
- }
- return false;
- }
-
- static final Map<String, Boolean> PRIMITIVE_TYPE = new HashMap<String, Boolean>() {
- {
- put(Boolean.class.getName(), true);
- put(Character.class.getName(), true);
- put(Byte.class.getName(), true);
- put(Short.class.getName(), true);
- put(Integer.class.getName(), true);
- put(Long.class.getName(), true);
- put(Float.class.getName(), true);
- put(Double.class.getName(), true);
- put(Void.class.getName(), true);
- }
- };
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java
index 3fe18a7..ab89f94 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/JavaSerializer.java
@@ -48,13 +48,16 @@
package com.alibaba.com.caucho.hessian.io;
+import com.alibaba.com.caucho.hessian.HessianUnshared;
+
import java.io.IOException;
+import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
+import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -65,7 +68,8 @@
private static final Logger log
= Logger.getLogger(JavaSerializer.class.getName());
- private static Object[] NULL_ARGS = new Object[0];
+ private static final WeakHashMap<Class<?>, SoftReference<JavaSerializer>> _serializerMap
+ = new WeakHashMap<Class<?>, SoftReference<JavaSerializer>>();
private Field[] _fields;
private FieldSerializer[] _fieldSerializers;
@@ -73,63 +77,48 @@
private Object _writeReplaceFactory;
private Method _writeReplace;
- public JavaSerializer(Class cl, ClassLoader loader) {
- introspectWriteReplace(cl, loader);
+ public JavaSerializer(Class<?> cl) {
+ introspect(cl);
+
+ _writeReplace = getWriteReplace(cl);
if (_writeReplace != null)
_writeReplace.setAccessible(true);
+ }
- List primitiveFields = new ArrayList();
- List compoundFields = new ArrayList();
+ public static Serializer create(Class<?> cl) {
+ synchronized (_serializerMap) {
+ SoftReference<JavaSerializer> baseRef
+ = _serializerMap.get(cl);
- for (; cl != null; cl = cl.getSuperclass()) {
- Field[] fields = cl.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- Field field = fields[i];
+ JavaSerializer base = baseRef != null ? baseRef.get() : null;
- if (Modifier.isTransient(field.getModifiers())
- || Modifier.isStatic(field.getModifiers()))
- continue;
-
- // XXX: could parameterize the handler to only deal with public
- field.setAccessible(true);
-
- if (field.getType().isPrimitive()
- || (field.getType().getName().startsWith("java.lang.")
- && !field.getType().equals(Object.class)))
- primitiveFields.add(field);
+ if (base == null) {
+ if (cl.isAnnotationPresent(HessianUnshared.class))
+ base = new JavaUnsharedSerializer(cl);
else
- compoundFields.add(field);
+ base = new JavaSerializer(cl);
+
+ baseRef = new SoftReference<JavaSerializer>(base);
+ _serializerMap.put(cl, baseRef);
}
- }
- List fields = new ArrayList();
- fields.addAll(primitiveFields);
- fields.addAll(compoundFields);
- Collections.reverse(fields);
-
- _fields = new Field[fields.size()];
- fields.toArray(_fields);
-
- _fieldSerializers = new FieldSerializer[_fields.length];
-
- for (int i = 0; i < _fields.length; i++) {
- _fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
+ return base;
}
}
/**
* Returns the writeReplace method
*/
- protected static Method getWriteReplace(Class cl) {
+ public static Method getWriteReplace(Class<?> cl) {
for (; cl != null; cl = cl.getSuperclass()) {
Method[] methods = cl.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
- if (method.getName().equals("writeReplace") &&
- method.getParameterTypes().length == 0)
+ if (method.getName().equals("writeReplace")
+ && method.getParameterTypes().length == 0)
return method;
}
}
@@ -137,7 +126,7 @@
return null;
}
- private static FieldSerializer getFieldSerializer(Class type) {
+ private static FieldSerializer getFieldSerializer(Class<?> type) {
if (int.class.equals(type)
|| byte.class.equals(type)
|| short.class.equals(type)
@@ -161,34 +150,53 @@
return FieldSerializer.SER;
}
- private void introspectWriteReplace(Class cl, ClassLoader loader) {
- try {
- String className = cl.getName() + "HessianSerializer";
+ protected void introspect(Class<?> cl) {
+ if (_writeReplace != null)
+ _writeReplace.setAccessible(true);
- Class serializerClass = Class.forName(className, false, loader);
+ ArrayList<Field> primitiveFields = new ArrayList<Field>();
+ ArrayList<Field> compoundFields = new ArrayList<Field>();
- Object serializerObject = serializerClass.newInstance();
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field[] fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
- Method writeReplace = getWriteReplace(serializerClass, cl);
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers()))
+ continue;
- if (writeReplace != null) {
- _writeReplaceFactory = serializerObject;
- _writeReplace = writeReplace;
+ // XXX: could parameterize the handler to only deal with public
+ field.setAccessible(true);
- return;
+ if (field.getType().isPrimitive()
+ || (field.getType().getName().startsWith("java.lang.")
+ && !field.getType().equals(Object.class)))
+ primitiveFields.add(field);
+ else
+ compoundFields.add(field);
}
- } catch (ClassNotFoundException e) {
- } catch (Exception e) {
- log.log(Level.FINER, e.toString(), e);
}
- _writeReplace = getWriteReplace(cl);
+ ArrayList<Field> fields = new ArrayList<Field>();
+ fields.addAll(primitiveFields);
+ fields.addAll(compoundFields);
+ Collections.reverse(fields);
+
+ _fields = new Field[fields.size()];
+ fields.toArray(_fields);
+
+ _fieldSerializers = new FieldSerializer[_fields.length];
+
+ for (int i = 0; i < _fields.length; i++) {
+ _fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
+ }
}
/**
* Returns the writeReplace method
*/
- protected Method getWriteReplace(Class cl, Class param) {
+ protected Method getWriteReplace(Class<?> cl, Class<?> param) {
for (; cl != null; cl = cl.getSuperclass()) {
for (Method method : cl.getDeclaredMethods()) {
if (method.getName().equals("writeReplace")
@@ -208,7 +216,7 @@
return;
}
- Class cl = obj.getClass();
+ Class<?> cl = obj.getClass();
try {
if (_writeReplace != null) {
@@ -219,17 +227,29 @@
else
repl = _writeReplace.invoke(obj);
- //Some class would return itself for wrapReplace, which would cause infinite recursion
- //In this case, we could write the object just like normal cases
- if (repl != obj) {
- out.removeRef(obj);
+ // out.removeRef(obj);
- out.writeObject(repl);
+ /*
+ out.writeObject(repl);
- out.replaceRef(repl, obj);
+ out.replaceRef(repl, obj);
+ */
- return;
+ //hessian/3a5a
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ writeObject10(repl, out);
+ } else {
+ if (ref == -1) {
+ writeDefinition20(out);
+ out.writeObjectBegin(cl.getName());
+ }
+
+ writeInstance(repl, out);
}
+
+ return;
}
} catch (RuntimeException e) {
throw e;
@@ -252,7 +272,7 @@
}
}
- private void writeObject10(Object obj, AbstractHessianOutput out)
+ protected void writeObject10(Object obj, AbstractHessianOutput out)
throws IOException {
for (int i = 0; i < _fields.length; i++) {
Field field = _fields[i];
@@ -276,12 +296,23 @@
}
}
+ @Override
public void writeInstance(Object obj, AbstractHessianOutput out)
throws IOException {
- for (int i = 0; i < _fields.length; i++) {
- Field field = _fields[i];
+ try {
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
- _fieldSerializers[i].serialize(out, obj, field);
+ _fieldSerializers[i].serialize(out, obj, field);
+ }
+ } catch (RuntimeException e) {
+ throw new RuntimeException(e.getMessage() + "\n class: "
+ + obj.getClass().getName(),
+ e);
+ } catch (IOException e) {
+ throw new IOExceptionWrapper(e.getMessage() + "\n class: "
+ + obj.getClass().getName(),
+ e);
}
}
@@ -301,10 +332,14 @@
try {
out.writeObject(value);
} catch (RuntimeException e) {
- throw new RuntimeException(e.getMessage() + "\n Java field: " + field,
+ throw new RuntimeException(e.getMessage() + "\n field: "
+ + field.getDeclaringClass().getName()
+ + '.' + field.getName(),
e);
} catch (IOException e) {
- throw new IOExceptionWrapper(e.getMessage() + "\n Java field: " + field,
+ throw new IOExceptionWrapper(e.getMessage() + "\n field: "
+ + field.getDeclaringClass().getName()
+ + '.' + field.getName(),
e);
}
}
@@ -313,7 +348,6 @@
static class BooleanFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new BooleanFieldSerializer();
- @Override
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
boolean value = false;
@@ -331,7 +365,6 @@
static class IntFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new IntFieldSerializer();
- @Override
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
int value = 0;
@@ -349,7 +382,6 @@
static class LongFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new LongFieldSerializer();
- @Override
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
long value = 0;
@@ -367,7 +399,6 @@
static class DoubleFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new DoubleFieldSerializer();
- @Override
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
double value = 0;
@@ -385,7 +416,6 @@
static class StringFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new StringFieldSerializer();
- @Override
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
String value = null;
@@ -403,7 +433,6 @@
static class DateFieldSerializer extends FieldSerializer {
static final FieldSerializer SER = new DateFieldSerializer();
- @Override
void serialize(AbstractHessianOutput out, Object obj, Field field)
throws IOException {
java.util.Date value = null;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/JavaUnsharedSerializer.java
similarity index 75%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/JavaUnsharedSerializer.java
index 72a9822..ff95fa2 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/JavaUnsharedSerializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -49,17 +49,28 @@
package com.alibaba.com.caucho.hessian.io;
import java.io.IOException;
+import java.util.logging.Logger;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object for known object types.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class JavaUnsharedSerializer extends JavaSerializer {
+ private static final Logger log
+ = Logger.getLogger(JavaUnsharedSerializer.class.getName());
+
+ public JavaUnsharedSerializer(Class<?> cl) {
+ super(cl);
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ boolean oldUnshared = out.setUnshared(true);
+
+ try {
+ super.writeObject(obj, out);
+ } finally {
+ out.setUnshared(oldUnshared);
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java b/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java
index 751eee6..880f0a5 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleHandle.java
@@ -48,6 +48,7 @@
package com.alibaba.com.caucho.hessian.io;
+
import java.util.Locale;
/**
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java
index 2ac9393..c757288 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/LocaleSerializer.java
@@ -48,6 +48,7 @@
package com.alibaba.com.caucho.hessian.io;
+
import java.io.IOException;
import java.util.Locale;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java
index 9720fb6..bfe4cb5 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/MapDeserializer.java
@@ -50,7 +50,6 @@
import java.io.IOException;
import java.lang.reflect.Constructor;
-import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
@@ -60,16 +59,16 @@
* Deserializing a JDK 1.2 Map.
*/
public class MapDeserializer extends AbstractMapDeserializer {
- private Class _type;
- private Constructor _ctor;
+ private Class<?> _type;
+ private Constructor<?> _ctor;
- public MapDeserializer(Class type) {
+ public MapDeserializer(Class<?> type) {
if (type == null)
type = HashMap.class;
_type = type;
- Constructor[] ctors = type.getConstructors();
+ Constructor<?>[] ctors = type.getConstructors();
for (int i = 0; i < ctors.length; i++) {
if (ctors[i].getParameterTypes().length == 0)
_ctor = ctors[i];
@@ -84,27 +83,15 @@
}
}
- @Override
- public Class getType() {
+ public Class<?> getType() {
if (_type != null)
return _type;
else
return HashMap.class;
}
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
- return readMap(in, null, null);
- }
-
- /**
- * support generic type of map, fix the type of short serialization <p>
- * eg: Map<String, Short> serialize & deserialize
- *
- */
- @Override
- public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType) throws IOException {
Map map;
if (_type == null)
@@ -123,35 +110,21 @@
in.addRef(map);
- doReadMap(in, map, expectKeyType, expectValueType);
+ while (!in.isEnd()) {
+ map.put(in.readObject(), in.readObject());
+ }
in.readEnd();
return map;
}
- protected void doReadMap(AbstractHessianInput in, Map map, Class<?> keyType, Class<?> valueType) throws IOException {
- Deserializer keyDeserializer = null, valueDeserializer = null;
-
- SerializerFactory factory = findSerializerFactory(in);
- if(keyType != null){
- keyDeserializer = factory.getDeserializer(keyType.getName());
- }
- if(valueType != null){
- valueDeserializer = factory.getDeserializer(valueType.getName());
- }
-
- while (!in.isEnd()) {
- map.put(keyDeserializer != null ? keyDeserializer.readObject(in) : in.readObject(),
- valueDeserializer != null? valueDeserializer.readObject(in) : in.readObject());
- }
- }
-
@Override
public Object readObject(AbstractHessianInput in,
- String[] fieldNames)
+ Object[] fields)
throws IOException {
- Map map = createMap();
+ String[] fieldNames = (String[]) fields;
+ Map<Object, Object> map = createMap();
int ref = in.addRef(map);
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java
index 5d48eaa..95d4869 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/MapSerializer.java
@@ -73,7 +73,6 @@
_isSendJavaType = sendJavaType;
}
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
if (out.addRef(obj))
@@ -81,14 +80,28 @@
Map map = (Map) obj;
- Class cl = obj.getClass();
+ Class<?> cl = obj.getClass();
if (cl.equals(HashMap.class)
- || !_isSendJavaType
|| !(obj instanceof java.io.Serializable))
out.writeMapBegin(null);
- else
- out.writeMapBegin(obj.getClass().getName());
+ else if (!_isSendJavaType) {
+ // hessian/3a19
+ for (; cl != null; cl = cl.getSuperclass()) {
+ if (cl.equals(HashMap.class)) {
+ out.writeMapBegin(null);
+ break;
+ } else if (cl.getName().startsWith("java.")) {
+ out.writeMapBegin(cl.getName());
+ break;
+ }
+ }
+
+ if (cl == null)
+ out.writeMapBegin(null);
+ } else {
+ out.writeMapBegin(cl.getName());
+ }
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java
index c4e69f1..03230e8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectDeserializer.java
@@ -54,14 +54,13 @@
* Serializing an object for known object types.
*/
public class ObjectDeserializer extends AbstractDeserializer {
- private Class _cl;
+ private Class<?> _cl;
- public ObjectDeserializer(Class cl) {
+ public ObjectDeserializer(Class<?> cl) {
_cl = cl;
}
- @Override
- public Class getType() {
+ public Class<?> getType() {
return _cl;
}
@@ -72,7 +71,7 @@
}
@Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object readObject(AbstractHessianInput in, Object[] fields)
throws IOException {
throw new UnsupportedOperationException(String.valueOf(this));
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectHandleSerializer.java
similarity index 77%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/ObjectHandleSerializer.java
index 72a9822..b135aa3 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectHandleSerializer.java
@@ -51,15 +51,29 @@
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a remote object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
+public class ObjectHandleSerializer extends AbstractSerializer {
+ public static final Serializer SER = new ObjectHandleSerializer();
+
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ if (out.addRef(obj))
+ return;
+
+ int ref = out.writeObjectBegin("object");
+
+ if (ref < -1) {
+ out.writeMapEnd();
+ } else {
+ if (ref == -1) {
+ out.writeInt(0);
+ out.writeObjectBegin("object");
+ }
+ }
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectNameDeserializer.java
similarity index 81%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/ObjectNameDeserializer.java
index 72a9822..b708ea6 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectNameDeserializer.java
@@ -48,18 +48,27 @@
package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
+import com.alibaba.com.caucho.hessian.HessianException;
+
+import javax.management.ObjectName;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing an ObjectName
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class ObjectNameDeserializer extends AbstractStringValueDeserializer {
@Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public Class<?> getType() {
+ return ObjectName.class;
+ }
+
+ @Override
+ protected Object create(String value) {
+ try {
+ return new ObjectName(value);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new HessianException(e);
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectSerializer.java
similarity index 90%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/ObjectSerializer.java
index be505fb..bfdf67a 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ObjectSerializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -48,9 +48,9 @@
package com.alibaba.com.caucho.hessian.io;
-import java.util.logging.Logger;
-
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Serializing an object.
+ */
+public interface ObjectSerializer {
+ public Serializer getObjectSerializer();
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteDeserializer.java
similarity index 68%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/RemoteDeserializer.java
index be505fb..07680ed 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteDeserializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -50,7 +50,34 @@
import java.util.logging.Logger;
-public class EnvelopeFactory {
+/**
+ * Serializing an object for known object types.
+ */
+public class RemoteDeserializer extends JavaDeserializer {
+ public static final Deserializer DESER = new RemoteDeserializer();
private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+ = Logger.getLogger(RemoteDeserializer.class.getName());
+
+ public RemoteDeserializer() {
+ super(HessianRemote.class, FieldDeserializer2Factory.create());
+ }
+
+ @Override
+ public boolean isReadResolve() {
+ return true;
+ }
+
+ @Override
+ protected Object resolve(AbstractHessianInput in, Object obj)
+ throws Exception {
+ HessianRemote remote = (HessianRemote) obj;
+ HessianRemoteResolver resolver = in.getRemoteResolver();
+
+ if (resolver != null) {
+ Object proxy = resolver.lookup(remote.getType(), remote.getURL());
+
+ return proxy;
+ } else
+ return remote;
+ }
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java
index 2914688..ae35809 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/RemoteSerializer.java
@@ -54,10 +54,11 @@
* Serializing a remote object.
*/
public class RemoteSerializer extends AbstractSerializer {
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- // XXX: needs to be handled as a separate class
- throw new UnsupportedOperationException(getClass().getName());
+ HessianRemoteObject remoteObject = (HessianRemoteObject) obj;
+
+ out.writeObject(new HessianRemote(remoteObject.getHessianType(),
+ remoteObject.getHessianURL()));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java b/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
index ac3bd18..45df1cf 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/SerializerFactory.java
@@ -48,36 +48,29 @@
package com.alibaba.com.caucho.hessian.io;
-import com.alibaba.com.caucho.hessian.io.java8.DurationHandle;
-import com.alibaba.com.caucho.hessian.io.java8.InstantHandle;
-import com.alibaba.com.caucho.hessian.io.java8.LocalDateHandle;
-import com.alibaba.com.caucho.hessian.io.java8.LocalDateTimeHandle;
-import com.alibaba.com.caucho.hessian.io.java8.LocalTimeHandle;
-import com.alibaba.com.caucho.hessian.io.java8.MonthDayHandle;
-import com.alibaba.com.caucho.hessian.io.java8.OffsetDateTimeHandle;
-import com.alibaba.com.caucho.hessian.io.java8.OffsetTimeHandle;
-import com.alibaba.com.caucho.hessian.io.java8.PeriodHandle;
-import com.alibaba.com.caucho.hessian.io.java8.YearHandle;
-import com.alibaba.com.caucho.hessian.io.java8.YearMonthHandle;
import com.alibaba.com.caucho.hessian.io.java8.ZoneIdSerializer;
-import com.alibaba.com.caucho.hessian.io.java8.ZoneOffsetHandle;
-import com.alibaba.com.caucho.hessian.io.java8.ZonedDateTimeHandle;
-import javax.management.ObjectName;
-import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.*;
+import java.lang.annotation.Annotation;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
-import static com.alibaba.com.caucho.hessian.io.java8.Java8TimeSerializer.create;
-
/**
* Factory for returning serialization methods.
*/
@@ -85,16 +78,18 @@
private static final Logger log
= Logger.getLogger(SerializerFactory.class.getName());
- private static Deserializer OBJECT_DESERIALIZER
+ private static final Deserializer OBJECT_DESERIALIZER
= new BasicDeserializer(BasicDeserializer.OBJECT);
+ private static final ClassLoader _systemClassLoader;
+ private static final HashMap _staticTypeMap;
+ private static final
+ WeakHashMap<ClassLoader, SoftReference<SerializerFactory>>
+ _defaultFactoryRefMap
+ = new WeakHashMap<ClassLoader, SoftReference<SerializerFactory>>();
+ private static final Object PRESENT = new Object();
private static ConcurrentHashMap _unrecognizedTypeCache = new ConcurrentHashMap();
- private static HashMap _staticSerializerMap;
- private static HashMap _staticDeserializerMap;
- private static HashMap _staticTypeMap;
static {
- _staticSerializerMap = new HashMap();
- _staticDeserializerMap = new HashMap();
_staticTypeMap = new HashMap();
addBasic(void.class, "void", BasicSerializer.NULL);
@@ -108,6 +103,7 @@
addBasic(Double.class, "double", BasicSerializer.DOUBLE);
addBasic(Character.class, "char", BasicSerializer.CHARACTER_OBJECT);
addBasic(String.class, "string", BasicSerializer.STRING);
+ addBasic(StringBuilder.class, "string", BasicSerializer.STRING_BUILDER);
addBasic(Object.class, "object", BasicSerializer.OBJECT);
addBasic(java.util.Date.class, "date", BasicSerializer.DATE);
@@ -131,87 +127,19 @@
addBasic(String[].class, "[string", BasicSerializer.STRING_ARRAY);
addBasic(Object[].class, "[object", BasicSerializer.OBJECT_ARRAY);
- _staticSerializerMap.put(Class.class, new ClassSerializer());
+ Deserializer objectDeserializer = new JavaDeserializer(Object.class, new FieldDeserializer2Factory());
+ _staticTypeMap.put("object", objectDeserializer);
+ _staticTypeMap.put(HessianRemote.class.getName(),
+ RemoteDeserializer.DESER);
- _staticDeserializerMap.put(Number.class, new BasicDeserializer(BasicSerializer.NUMBER));
- _staticSerializerMap.put(BigDecimal.class, new StringValueSerializer());
+ ClassLoader systemClassLoader = null;
try {
- _staticDeserializerMap.put(BigDecimal.class,
- new StringValueDeserializer(BigDecimal.class));
- _staticDeserializerMap.put(BigInteger.class,
- new BigIntegerDeserializer());
- } catch (Throwable e) {
+ systemClassLoader = ClassLoader.getSystemClassLoader();
+ } catch (Exception e) {
}
-
- _staticSerializerMap.put(UUID.class, new StringValueSerializer());
- _staticDeserializerMap.put(UUID.class, new UUIDDeserializer());
-
- _staticSerializerMap.put(File.class, new StringValueSerializer());
- try {
- _staticDeserializerMap.put(File.class,
- new StringValueDeserializer(File.class));
- } catch (Throwable e) {
- }
-
- _staticSerializerMap.put(ObjectName.class, new StringValueSerializer());
- try {
- _staticDeserializerMap.put(ObjectName.class,
- new StringValueDeserializer(ObjectName.class));
- } catch (Throwable e) {
- }
-
- _staticSerializerMap.put(java.sql.Date.class, new SqlDateSerializer());
- _staticSerializerMap.put(java.sql.Time.class, new SqlDateSerializer());
- _staticSerializerMap.put(java.sql.Timestamp.class, new SqlDateSerializer());
-
- _staticSerializerMap.put(java.io.InputStream.class,
- new InputStreamSerializer());
- _staticDeserializerMap.put(java.io.InputStream.class,
- new InputStreamDeserializer());
-
- try {
- _staticDeserializerMap.put(java.sql.Date.class,
- new SqlDateDeserializer(java.sql.Date.class));
- _staticDeserializerMap.put(java.sql.Time.class,
- new SqlDateDeserializer(java.sql.Time.class));
- _staticDeserializerMap.put(java.sql.Timestamp.class,
- new SqlDateDeserializer(java.sql.Timestamp.class));
- } catch (Throwable e) {
- e.printStackTrace();
- }
-
- // hessian/3bb5
- try {
- Class stackTrace = StackTraceElement.class;
-
- _staticDeserializerMap.put(stackTrace, new StackTraceElementDeserializer());
- } catch (Throwable e) {
- }
-
- try {
- if (isJava8()) {
- _staticSerializerMap.put(Class.forName("java.time.LocalTime"), create(LocalTimeHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.LocalDate"), create(LocalDateHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.LocalDateTime"), create(LocalDateTimeHandle.class));
-
- _staticSerializerMap.put(Class.forName("java.time.Instant"), create(InstantHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.Duration"), create(DurationHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.Period"), create(PeriodHandle.class));
-
- _staticSerializerMap.put(Class.forName("java.time.Year"), create(YearHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.YearMonth"), create(YearMonthHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.MonthDay"), create(MonthDayHandle.class));
-
- _staticSerializerMap.put(Class.forName("java.time.OffsetDateTime"), create(OffsetDateTimeHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.ZoneOffset"), create(ZoneOffsetHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.OffsetTime"), create(OffsetTimeHandle.class));
- _staticSerializerMap.put(Class.forName("java.time.ZonedDateTime"), create(ZonedDateTimeHandle.class));
- }
- } catch (Throwable t) {
- log.warning(String.valueOf(t.getCause()));
- }
+ _systemClassLoader = systemClassLoader;
}
protected Serializer _defaultSerializer;
@@ -221,20 +149,23 @@
protected CollectionSerializer _collectionSerializer;
protected MapSerializer _mapSerializer;
- private ClassLoader _loader;
+ private ContextSerializerFactory _contextFactory;
+ private WeakReference<ClassLoader> _loaderRef;
private Deserializer _hashMapDeserializer;
private Deserializer _arrayListDeserializer;
- private ConcurrentHashMap _cachedSerializerMap;
- private ConcurrentHashMap _cachedDeserializerMap;
- private ConcurrentHashMap _cachedTypeDeserializerMap;
+ private Map _cachedSerializerMap;
+ private Map _cachedDeserializerMap;
+ private HashMap _cachedTypeDeserializerMap;
private boolean _isAllowNonSerializable;
+ private boolean _isEnableUnsafeSerializer
+ = (UnsafeSerializer.isEnabled()
+ && UnsafeDeserializer.isEnabled());
/**
* For those classes are unknown in current classloader, record them in this set to avoid
* frequently class loading and to reduce performance overhead.
*/
private Map<String, Object> _typeNotFoundDeserializerMap = new ConcurrentHashMap<>(8);
- private static final Object PRESENT = new Object();
-
+ private FieldDeserializer2Factory _fieldDeserializerFactory;
private ClassFactory _classFactory;
public SerializerFactory() {
@@ -242,36 +173,68 @@
}
public SerializerFactory(ClassLoader loader) {
- _loader = loader;
- }
+ _loaderRef = new WeakReference<ClassLoader>(loader);
- public Class<?> loadSerializedClass(String className)
- throws ClassNotFoundException
- {
- return getClassFactory().load(className);
- }
+ _contextFactory = ContextSerializerFactory.create(loader);
- public ClassFactory getClassFactory()
- {
- synchronized (this) {
- if (_classFactory == null) {
- _classFactory = new ClassFactory(getClassLoader());
- }
-
- return _classFactory;
+ if (_isEnableUnsafeSerializer) {
+ _fieldDeserializerFactory = new FieldDeserializer2FactoryUnsafe();
+ } else {
+ _fieldDeserializerFactory = new FieldDeserializer2Factory();
}
}
- private static void addBasic(Class cl, String typeName, int type) {
- _staticSerializerMap.put(cl, new BasicSerializer(type));
+ public static SerializerFactory createDefault() {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ synchronized (_defaultFactoryRefMap) {
+ SoftReference<SerializerFactory> factoryRef
+ = _defaultFactoryRefMap.get(loader);
+
+ SerializerFactory factory = null;
+
+ if (factoryRef != null)
+ factory = factoryRef.get();
+
+ if (factory == null) {
+ factory = new SerializerFactory();
+
+ factoryRef = new SoftReference<SerializerFactory>(factory);
+
+ _defaultFactoryRefMap.put(loader, factoryRef);
+ }
+
+ return factory;
+ }
+ }
+
+ private static void addBasic(Class<?> cl, String typeName, int type) {
Deserializer deserializer = new BasicDeserializer(type);
- _staticDeserializerMap.put(cl, deserializer);
+
_staticTypeMap.put(typeName, deserializer);
}
+ private static boolean isZoneId(Class cl) {
+ try {
+ return isJava8() && Class.forName("java.time.ZoneId").isAssignableFrom(cl);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ return false;
+ }
+
+ /**
+ * check if the environment is java 8 or beyond
+ *
+ * @return if on java 8
+ */
+ private static boolean isJava8() {
+ String javaVersion = System.getProperty("java.specification.version");
+ return Double.valueOf(javaVersion) >= 1.8;
+ }
+
public ClassLoader getClassLoader() {
- return _loader;
+ return _loaderRef.get();
}
/**
@@ -316,90 +279,152 @@
* @param cl the class of the object that needs to be serialized.
* @return a serializer object for the serialization.
*/
- @Override
+ public Serializer getObjectSerializer(Class<?> cl)
+ throws HessianProtocolException {
+ Serializer serializer = getSerializer(cl);
+
+ if (serializer instanceof ObjectSerializer)
+ return ((ObjectSerializer) serializer).getObjectSerializer();
+ else
+ return serializer;
+ }
+
+ public Class<?> loadSerializedClass(String className)
+ throws ClassNotFoundException {
+ return getClassFactory().load(className);
+ }
+
+ public ClassFactory getClassFactory() {
+ synchronized (this) {
+ if (_classFactory == null) {
+ _classFactory = new ClassFactory(getClassLoader());
+ }
+
+ return _classFactory;
+ }
+ }
+
+ public FieldDeserializer2Factory getFieldDeserializerFactory() {
+ return _fieldDeserializerFactory;
+ }
+
+ public boolean isEnableUnsafeSerializer() {
+ return _isEnableUnsafeSerializer;
+ }
+
+ /**
+ * Returns the serializer for a class.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ * @return a serializer object for the serialization.
+ */
public Serializer getSerializer(Class cl)
throws HessianProtocolException {
Serializer serializer;
- serializer = (Serializer) _staticSerializerMap.get(cl);
- if (serializer != null) {
- return serializer;
- }
-
if (_cachedSerializerMap != null) {
serializer = (Serializer) _cachedSerializerMap.get(cl);
+
if (serializer != null) {
return serializer;
}
}
+ serializer = loadSerializer(cl);
+
+ if (_cachedSerializerMap == null)
+ _cachedSerializerMap = new ConcurrentHashMap(8);
+
+ _cachedSerializerMap.put(cl, serializer);
+
+ return serializer;
+ }
+
+ protected Serializer loadSerializer(Class<?> cl)
+ throws HessianProtocolException {
+ Serializer serializer = null;
+
for (int i = 0;
- serializer == null && _factories != null && i < _factories.size();
+ _factories != null && i < _factories.size();
i++) {
AbstractSerializerFactory factory;
factory = (AbstractSerializerFactory) _factories.get(i);
serializer = factory.getSerializer(cl);
+
+ if (serializer != null)
+ return serializer;
}
+ serializer = _contextFactory.getSerializer(cl.getName());
+
+ if (serializer != null)
+ return serializer;
+
+ ClassLoader loader = cl.getClassLoader();
+
+ if (loader == null)
+ loader = _systemClassLoader;
+
+ ContextSerializerFactory factory = null;
+
+ factory = ContextSerializerFactory.create(loader);
+
+ serializer = factory.getCustomSerializer(cl);
+
if (serializer != null) {
+ return serializer;
+ }
+ if (HessianRemoteObject.class.isAssignableFrom(cl)) {
+ return new RemoteSerializer();
+ } else if (InetAddress.class.isAssignableFrom(cl)) {
+ return InetAddressSerializer.create();
} else if (isZoneId(cl)) //must before "else if (JavaSerializer.getWriteReplace(cl) != null)"
- serializer = ZoneIdSerializer.getInstance();
- else if (isEnumSet(cl))
- serializer = EnumSetSerializer.getInstance();
- else if (JavaSerializer.getWriteReplace(cl) != null)
- serializer = new JavaSerializer(cl, _loader);
+ return ZoneIdSerializer.getInstance();
+ else if (JavaSerializer.getWriteReplace(cl) != null) {
+ Serializer baseSerializer = getDefaultSerializer(cl);
- else if (HessianRemoteObject.class.isAssignableFrom(cl))
- serializer = new RemoteSerializer();
-
-// else if (BurlapRemoteObject.class.isAssignableFrom(cl))
-// serializer = new RemoteSerializer();
-
- else if (Map.class.isAssignableFrom(cl)) {
+ return new WriteReplaceSerializer(cl, getClassLoader(), baseSerializer);
+ } else if (Map.class.isAssignableFrom(cl)) {
if (_mapSerializer == null)
_mapSerializer = new MapSerializer();
- serializer = _mapSerializer;
+ return _mapSerializer;
} else if (Collection.class.isAssignableFrom(cl)) {
if (_collectionSerializer == null) {
_collectionSerializer = new CollectionSerializer();
}
- serializer = _collectionSerializer;
+ return _collectionSerializer;
} else if (cl.isArray()) {
- serializer = new ArraySerializer();
- } else if (Throwable.class.isAssignableFrom(cl)) {
- serializer = new ThrowableSerializer(cl, getClassLoader());
- } else if (InputStream.class.isAssignableFrom(cl)) {
- serializer = new InputStreamSerializer();
- } else if (Iterator.class.isAssignableFrom(cl)) {
- serializer = IteratorSerializer.create();
- } else if (Enumeration.class.isAssignableFrom(cl)) {
- serializer = EnumerationSerializer.create();
- } else if (Calendar.class.isAssignableFrom(cl)) {
- serializer = CalendarSerializer.create();
- } else if (Locale.class.isAssignableFrom(cl)) {
- serializer = LocaleSerializer.create();
- } else if (Enum.class.isAssignableFrom(cl)) {
- serializer = new EnumSerializer(cl);
- } else if (BitSet.class.isAssignableFrom(cl)) {
- serializer = BitSetSerializer.create();
- }
+ return new ArraySerializer();
+ } else if (Throwable.class.isAssignableFrom(cl))
+ return new ThrowableSerializer(getDefaultSerializer(cl));
- if (serializer == null) {
- serializer = getDefaultSerializer(cl);
- }
+ else if (InputStream.class.isAssignableFrom(cl))
+ return new InputStreamSerializer();
- if (_cachedSerializerMap == null) {
- _cachedSerializerMap = new ConcurrentHashMap(8);
- }
+ else if (Iterator.class.isAssignableFrom(cl))
+ return IteratorSerializer.create();
- _cachedSerializerMap.put(cl, serializer);
+ else if (Calendar.class.isAssignableFrom(cl))
+ return CalendarSerializer.SER;
- return serializer;
+ else if (Enumeration.class.isAssignableFrom(cl))
+ return EnumerationSerializer.create();
+
+ else if (Enum.class.isAssignableFrom(cl))
+ return new EnumSerializer(cl);
+
+ else if (Annotation.class.isAssignableFrom(cl))
+ return new AnnotationSerializer(cl);
+
+ else if (BitSet.class.isAssignableFrom(cl))
+ return BitSetSerializer.create();
+
+ return getDefaultSerializer(cl);
}
/**
@@ -419,7 +444,11 @@
throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");
}
- return new JavaSerializer(cl, _loader);
+ if (_isEnableUnsafeSerializer
+ && JavaSerializer.getWriteReplace(cl) == null) {
+ return UnsafeSerializer.create(cl);
+ } else
+ return JavaSerializer.create(cl);
}
/**
@@ -428,21 +457,30 @@
* @param cl the class of the object that needs to be deserialized.
* @return a deserializer object for the serialization.
*/
- @Override
public Deserializer getDeserializer(Class cl)
throws HessianProtocolException {
Deserializer deserializer;
- deserializer = (Deserializer) _staticDeserializerMap.get(cl);
- if (deserializer != null)
- return deserializer;
-
if (_cachedDeserializerMap != null) {
deserializer = (Deserializer) _cachedDeserializerMap.get(cl);
+
if (deserializer != null)
return deserializer;
}
+ deserializer = loadDeserializer(cl);
+
+ if (_cachedDeserializerMap == null)
+ _cachedDeserializerMap = new ConcurrentHashMap(8);
+
+ _cachedDeserializerMap.put(cl, deserializer);
+
+ return deserializer;
+ }
+
+ protected Deserializer loadDeserializer(Class cl)
+ throws HessianProtocolException {
+ Deserializer deserializer = null;
for (int i = 0;
deserializer == null && _factories != null && i < _factories.size();
@@ -453,40 +491,85 @@
deserializer = factory.getDeserializer(cl);
}
- if (deserializer != null) {
- } else if (Collection.class.isAssignableFrom(cl))
+ if (deserializer != null)
+ return deserializer;
+
+ // XXX: need test
+ deserializer = _contextFactory.getDeserializer(cl.getName());
+
+ if (deserializer != null)
+ return deserializer;
+
+ ContextSerializerFactory factory = null;
+
+ if (cl.getClassLoader() != null)
+ factory = ContextSerializerFactory.create(cl.getClassLoader());
+ else
+ factory = ContextSerializerFactory.create(_systemClassLoader);
+
+ deserializer = factory.getDeserializer(cl.getName());
+
+ if (deserializer != null)
+ return deserializer;
+
+ deserializer = factory.getCustomDeserializer(cl);
+
+ if (deserializer != null)
+ return deserializer;
+
+ if (Collection.class.isAssignableFrom(cl))
deserializer = new CollectionDeserializer(cl);
- else if (Map.class.isAssignableFrom(cl))
+ else if (Map.class.isAssignableFrom(cl)) {
deserializer = new MapDeserializer(cl);
-
- else if (cl.isInterface())
+ } else if (Iterator.class.isAssignableFrom(cl)) {
+ deserializer = IteratorDeserializer.create();
+ } else if (Annotation.class.isAssignableFrom(cl)) {
+ deserializer = new AnnotationDeserializer(cl);
+ } else if (cl.isInterface()) {
deserializer = new ObjectDeserializer(cl);
-
- else if (cl.isArray())
+ } else if (cl.isArray()) {
deserializer = new ArrayDeserializer(cl.getComponentType());
-
- else if (Enumeration.class.isAssignableFrom(cl))
+ } else if (Enumeration.class.isAssignableFrom(cl)) {
deserializer = EnumerationDeserializer.create();
-
- else if (Enum.class.isAssignableFrom(cl))
+ } else if (Enum.class.isAssignableFrom(cl))
deserializer = new EnumDeserializer(cl);
else if (Class.class.equals(cl))
- deserializer = new ClassDeserializer(_loader);
+ deserializer = new ClassDeserializer(getClassLoader());
else
deserializer = getDefaultDeserializer(cl);
- if (_cachedDeserializerMap == null)
- _cachedDeserializerMap = new ConcurrentHashMap(8);
-
- _cachedDeserializerMap.put(cl, deserializer);
-
return deserializer;
}
/**
+ * Returns a custom serializer the class
+ *
+ * @param cl the class of the object that needs to be serialized.
+ * @return a serializer object for the serialization.
+ */
+ protected Deserializer getCustomDeserializer(Class cl) {
+ try {
+ Class serClass = Class.forName(cl.getName() + "HessianDeserializer",
+ false, cl.getClassLoader());
+
+ Deserializer ser = (Deserializer) serClass.newInstance();
+
+ return ser;
+ } catch (ClassNotFoundException e) {
+ log.log(Level.FINEST, e.toString(), e);
+
+ return null;
+ } catch (Exception e) {
+ log.log(Level.FINE, e.toString(), e);
+
+ return null;
+ }
+ }
+
+ /**
* Returns the default serializer for a class that isn't matched
* directly. Application can override this method to produce
* bean-style serialization instead of field serialization.
@@ -495,12 +578,18 @@
* @return a serializer object for the serialization.
*/
protected Deserializer getDefaultDeserializer(Class cl) {
+ if (InputStream.class.equals(cl))
+ return InputStreamDeserializer.DESER;
+
if (!Serializable.class.isAssignableFrom(cl)
&& !_isAllowNonSerializable) {
throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");
}
- return new JavaDeserializer(cl);
+ if (_isEnableUnsafeSerializer) {
+ return new UnsafeDeserializer(cl, _fieldDeserializerFactory);
+ } else
+ return new JavaDeserializer(cl, _fieldDeserializerFactory);
}
/**
@@ -521,24 +610,16 @@
*/
public Object readMap(AbstractHessianInput in, String type)
throws HessianProtocolException, IOException {
- return readMap(in, type, null, null);
- }
-
- /**
- * Reads the object as a map.
- */
- public Object readMap(AbstractHessianInput in, String type, Class<?> expectKeyType, Class<?> expectValueType)
- throws HessianProtocolException, IOException {
Deserializer deserializer = getDeserializer(type);
if (deserializer != null)
return deserializer.readMap(in);
else if (_hashMapDeserializer != null)
- return _hashMapDeserializer.readMap(in, expectKeyType, expectValueType);
+ return _hashMapDeserializer.readMap(in);
else {
_hashMapDeserializer = new MapDeserializer(HashMap.class);
- return _hashMapDeserializer.readMap(in, expectKeyType, expectValueType);
+ return _hashMapDeserializer.readMap(in);
}
}
@@ -572,12 +653,13 @@
if (cl == null
|| cl.equals(reader.getType())
|| cl.isAssignableFrom(reader.getType())
+ || reader.isReadResolve()
|| HessianHandle.class.isAssignableFrom(reader.getType())) {
return reader;
}
if (log.isLoggable(Level.FINE)) {
- log.fine("hessian: expected '" + cl.getName() + "' at '" + type + "' ("
+ log.fine("hessian: expected deserializer '" + cl.getName() + "' at '" + type + "' ("
+ reader.getType().getName() + ")");
}
@@ -652,7 +734,9 @@
Deserializer deserializer;
if (_cachedTypeDeserializerMap != null) {
- deserializer = (Deserializer) _cachedTypeDeserializerMap.get(type);
+ synchronized (_cachedTypeDeserializerMap) {
+ deserializer = (Deserializer) _cachedTypeDeserializerMap.get(type);
+ }
if (deserializer != null)
return deserializer;
@@ -672,11 +756,13 @@
deserializer = new ArrayDeserializer(Object.class);
} else if (_unrecognizedTypeCache.get(type) == null) {
try {
-// Class cl = Class.forName(type, false, _loader);
+ //Class cl = Class.forName(type, false, getClassLoader());
+
Class cl = loadSerializedClass(type);
+
deserializer = getDeserializer(cl);
} catch (Exception e) {
- log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
+ log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + getClassLoader() + ":\n" + e);
_typeNotFoundDeserializerMap.put(type, PRESENT);
log.log(Level.FINER, e.toString(), e);
_unrecognizedTypeCache.put(type, new AtomicLong(1L));
@@ -689,34 +775,13 @@
if (deserializer != null) {
if (_cachedTypeDeserializerMap == null)
- _cachedTypeDeserializerMap = new ConcurrentHashMap(8);
+ _cachedTypeDeserializerMap = new HashMap(8);
- _cachedTypeDeserializerMap.put(type, deserializer);
+ synchronized (_cachedTypeDeserializerMap) {
+ _cachedTypeDeserializerMap.put(type, deserializer);
+ }
}
return deserializer;
}
-
- private static boolean isZoneId(Class cl) {
- try {
- return isJava8() && Class.forName("java.time.ZoneId").isAssignableFrom(cl);
- } catch (ClassNotFoundException e) {
- // ignore
- }
- return false;
- }
-
- private static boolean isEnumSet(Class cl) {
- return EnumSet.class.isAssignableFrom(cl);
- }
-
- /**
- * check if the environment is java 8 or beyond
- *
- * @return if on java 8
- */
- private static boolean isJava8() {
- String javaVersion = System.getProperty("java.specification.version");
- return Double.valueOf(javaVersion) >= 1.8;
- }
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ShortHandle.java
similarity index 80%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/ShortHandle.java
index 72a9822..d496822 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ShortHandle.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -48,18 +48,30 @@
package com.alibaba.com.caucho.hessian.io;
-import java.io.IOException;
+import java.io.Serializable;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Handle for Java Short objects.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+public class ShortHandle implements Serializable {
+ private short _value;
+
+ private ShortHandle() {
+ }
+
+ public ShortHandle(short value) {
+ _value = value;
+ }
+
+ public short getValue() {
+ return _value;
+ }
+
+ public Object readResolve() {
+ return new Short(_value);
+ }
+
+ public String toString() {
+ return getClass().getSimpleName() + "[" + _value + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java
index df809d7..2f0f8d8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateDeserializer.java
@@ -48,6 +48,8 @@
package com.alibaba.com.caucho.hessian.io;
+import com.alibaba.com.caucho.hessian.HessianException;
+
import java.io.IOException;
import java.lang.reflect.Constructor;
@@ -58,18 +60,19 @@
private Class _cl;
private Constructor _constructor;
- public SqlDateDeserializer(Class cl)
- throws NoSuchMethodException {
- _cl = cl;
- _constructor = cl.getConstructor(new Class[]{long.class});
+ public SqlDateDeserializer(Class cl) {
+ try {
+ _cl = cl;
+ _constructor = cl.getConstructor(new Class[]{long.class});
+ } catch (NoSuchMethodException e) {
+ throw new HessianException(e);
+ }
}
- @Override
public Class getType() {
return _cl;
}
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
int ref = in.addRef(null);
@@ -94,9 +97,11 @@
return value;
}
- @Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
throws IOException {
+ String[] fieldNames = (String[]) fields;
+
int ref = in.addRef(null);
long initValue = Long.MIN_VALUE;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java
index 5e6c8f4..c812c7e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/SqlDateSerializer.java
@@ -55,7 +55,6 @@
* Serializing a sql date object.
*/
public class SqlDateSerializer extends AbstractSerializer {
- @Override
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
if (obj == null)
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java
index 4f64859..0dbaa2c 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/StackTraceElementDeserializer.java
@@ -48,12 +48,19 @@
package com.alibaba.com.caucho.hessian.io;
+import java.lang.reflect.Constructor;
+
/**
* Deserializing a JDK 1.4 StackTraceElement
*/
public class StackTraceElementDeserializer extends JavaDeserializer {
- public StackTraceElementDeserializer() {
- super(StackTraceElement.class);
+ public StackTraceElementDeserializer(FieldDeserializer2Factory fieldFactory) {
+ super(StackTraceElement.class, fieldFactory);
+ }
+
+ @Override
+ protected Constructor<?> getConstructor(Class<?> cl) {
+ return null;
}
@Override
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java
index 90ceef1..5c01436 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueDeserializer.java
@@ -48,13 +48,15 @@
package com.alibaba.com.caucho.hessian.io;
+import com.alibaba.com.caucho.hessian.HessianException;
+
import java.io.IOException;
import java.lang.reflect.Constructor;
/**
* Deserializing a string valued object
*/
-public class StringValueDeserializer extends AbstractDeserializer {
+public class StringValueDeserializer extends AbstractStringValueDeserializer {
private Class _cl;
private Constructor _constructor;
@@ -73,48 +75,7 @@
}
@Override
- public Object readMap(AbstractHessianInput in)
- throws IOException {
- String value = null;
-
- while (!in.isEnd()) {
- String key = in.readString();
-
- if (key.equals("value"))
- value = in.readString();
- else
- in.readObject();
- }
-
- in.readMapEnd();
-
- Object object = create(value);
-
- in.addRef(object);
-
- return object;
- }
-
- @Override
- public Object readObject(AbstractHessianInput in, String[] fieldNames)
- throws IOException {
- String value = null;
-
- for (int i = 0; i < fieldNames.length; i++) {
- if ("value".equals(fieldNames[i]))
- value = in.readString();
- else
- in.readObject();
- }
-
- Object object = create(value);
-
- in.addRef(object);
-
- return object;
- }
-
- private Object create(String value)
+ protected Object create(String value)
throws IOException {
if (value == null)
throw new IOException(_cl.getName() + " expects name.");
@@ -122,7 +83,8 @@
try {
return _constructor.newInstance(new Object[]{value});
} catch (Exception e) {
- throw new IOExceptionWrapper(e);
+ throw new HessianException(_cl.getName() + ": value=" + value + "\n" + e,
+ e);
}
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java
index 16a00b4..42ac410 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/StringValueSerializer.java
@@ -54,7 +54,8 @@
* Serializing a remote object.
*/
public class StringValueSerializer extends AbstractSerializer {
- @Override
+ public static final Serializer SER = new StringValueSerializer();
+
public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
if (obj == null)
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java
index 1f65e7f..42c0e21 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ThrowableSerializer.java
@@ -53,9 +53,16 @@
/**
* Serializing an object for known object types.
*/
-public class ThrowableSerializer extends JavaSerializer {
- public ThrowableSerializer(Class cl, ClassLoader loader) {
- super(cl, loader);
+public class ThrowableSerializer extends AbstractSerializerWrapper {
+ private final Serializer _ser;
+
+ public ThrowableSerializer(Serializer ser) {
+ _ser = ser;
+ }
+
+ @Override
+ protected Serializer getDelegate() {
+ return _ser;
}
@Override
@@ -65,6 +72,6 @@
e.getStackTrace();
- super.writeObject(obj, out);
+ _ser.writeObject(obj, out);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeDeserializer.java
new file mode 100644
index 0000000..6b73277
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeDeserializer.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import com.alibaba.com.caucho.hessian.io.FieldDeserializer2FactoryUnsafe.NullFieldDeserializer;
+import sun.misc.Unsafe;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class UnsafeDeserializer extends AbstractMapDeserializer {
+ private static final Logger log
+ = Logger.getLogger(JavaDeserializer.class.getName());
+
+ private static boolean _isEnabled;
+ @SuppressWarnings("restriction")
+ private static Unsafe _unsafe;
+
+ static {
+ boolean isEnabled = false;
+
+ try {
+ Class<?> unsafe = Class.forName("sun.misc.Unsafe");
+ Field theUnsafe = null;
+ for (Field field : unsafe.getDeclaredFields()) {
+ if (field.getName().equals("theUnsafe"))
+ theUnsafe = field;
+ }
+
+ if (theUnsafe != null) {
+ theUnsafe.setAccessible(true);
+ _unsafe = (Unsafe) theUnsafe.get(null);
+ }
+
+ isEnabled = _unsafe != null;
+
+ String unsafeProp = System.getProperty("com.caucho.hessian.unsafe");
+
+ if ("false".equals(unsafeProp))
+ isEnabled = false;
+ } catch (Throwable e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ _isEnabled = isEnabled;
+ }
+
+ private Class<?> _type;
+ private HashMap<String, FieldDeserializer2> _fieldMap;
+ private Method _readResolve;
+
+ public UnsafeDeserializer(Class<?> cl, FieldDeserializer2Factory fieldFactory) {
+ _type = cl;
+ _fieldMap = getFieldMap(cl, fieldFactory);
+
+ _readResolve = getReadResolve(cl);
+
+ if (_readResolve != null) {
+ _readResolve.setAccessible(true);
+ }
+ }
+
+ public static boolean isEnabled() {
+ return _isEnabled;
+ }
+
+ static void logDeserializeError(Field field, Object obj, Object value,
+ Throwable e)
+ throws IOException {
+ String fieldName = (field.getDeclaringClass().getName()
+ + "." + field.getName());
+
+ if (e instanceof HessianFieldException)
+ throw (HessianFieldException) e;
+ else if (e instanceof IOException)
+ throw new HessianFieldException(fieldName + ": " + e.getMessage(), e);
+
+ if (value != null)
+ throw new HessianFieldException(fieldName + ": " + value.getClass().getName()
+ + " cannot be assigned to '" + field.getType().getName() + "'", e);
+ else
+ throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
+ }
+
+ @Override
+ public Class<?> getType() {
+ return _type;
+ }
+
+ @Override
+ public boolean isReadResolve() {
+ return _readResolve != null;
+ }
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readMap(in, obj);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Object[] createFields(int len) {
+ return new FieldDeserializer2[len];
+ }
+
+ public Object createField(String name) {
+ Object reader = _fieldMap.get(name);
+
+ if (reader == null)
+ reader = NullFieldDeserializer.DESER;
+
+ return reader;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ Object[] fields)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readObject(in, obj, (FieldDeserializer2[]) fields);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ String[] fieldNames)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readObject(in, obj, fieldNames);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Returns the readResolve method
+ */
+ protected Method getReadResolve(Class<?> cl) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("readResolve")
+ && method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ public Object readMap(AbstractHessianInput in, Object obj)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ while (!in.isEnd()) {
+ Object key = in.readObject();
+
+ FieldDeserializer2 deser = (FieldDeserializer2) _fieldMap.get(key);
+
+ if (deser != null)
+ deser.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object resolve = resolve(in, obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ Object obj,
+ FieldDeserializer2[] fields)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ for (FieldDeserializer2 reader : fields) {
+ reader.deserialize(in, obj);
+ }
+
+ Object resolve = resolve(in, obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ Object obj,
+ String[] fieldNames)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ for (String fieldName : fieldNames) {
+ FieldDeserializer2 reader = _fieldMap.get(fieldName);
+
+ if (reader != null)
+ reader.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ Object resolve = resolve(in, obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
+ }
+ }
+
+ protected Object resolve(AbstractHessianInput in, Object obj)
+ throws Exception {
+ // if there's a readResolve method, call it
+ try {
+ if (_readResolve != null)
+ return _readResolve.invoke(obj, new Object[0]);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof Exception)
+ throw (Exception) e.getCause();
+ else
+ throw e;
+ }
+
+ return obj;
+ }
+
+ @SuppressWarnings("restriction")
+ protected Object instantiate()
+ throws Exception {
+ return _unsafe.allocateInstance(_type);
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected HashMap<String, FieldDeserializer2>
+ getFieldMap(Class<?> cl, FieldDeserializer2Factory fieldFactory) {
+ HashMap<String, FieldDeserializer2> fieldMap
+ = new HashMap<String, FieldDeserializer2>();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field[] fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers()))
+ continue;
+ else if (fieldMap.get(field.getName()) != null)
+ continue;
+
+ /*
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ field.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ */
+
+ FieldDeserializer2 deser = fieldFactory.create(field);
+
+ fieldMap.put(field.getName(), deser);
+ }
+ }
+
+ return fieldMap;
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeSerializer.java
new file mode 100644
index 0000000..1668567
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeSerializer.java
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import com.alibaba.com.caucho.hessian.HessianUnshared;
+import sun.misc.Unsafe;
+
+import java.io.IOException;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.WeakHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class UnsafeSerializer extends AbstractSerializer {
+ private static final Logger log
+ = Logger.getLogger(UnsafeSerializer.class.getName());
+ private static final Unsafe _unsafe;
+ private static final WeakHashMap<Class<?>, SoftReference<UnsafeSerializer>> _serializerMap
+ = new WeakHashMap<Class<?>, SoftReference<UnsafeSerializer>>();
+ private static boolean _isEnabled;
+
+ static {
+ boolean isEnabled = false;
+ Unsafe unsafe = null;
+
+ try {
+ Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
+ Field theUnsafe = null;
+ for (Field field : unsafeClass.getDeclaredFields()) {
+ if (field.getName().equals("theUnsafe"))
+ theUnsafe = field;
+ }
+
+ if (theUnsafe != null) {
+ theUnsafe.setAccessible(true);
+ unsafe = (Unsafe) theUnsafe.get(null);
+ }
+
+ isEnabled = unsafe != null;
+
+ String unsafeProp = System.getProperty("com.caucho.hessian.unsafe");
+
+ if ("false".equals(unsafeProp))
+ isEnabled = false;
+ } catch (Throwable e) {
+ log.log(Level.ALL, e.toString(), e);
+ }
+
+ _unsafe = unsafe;
+ _isEnabled = isEnabled;
+ }
+
+ private Field[] _fields;
+ private FieldSerializer[] _fieldSerializers;
+
+ public UnsafeSerializer(Class<?> cl) {
+ introspect(cl);
+ }
+
+ public static boolean isEnabled() {
+ return _isEnabled;
+ }
+
+ public static UnsafeSerializer create(Class<?> cl) {
+ synchronized (_serializerMap) {
+ SoftReference<UnsafeSerializer> baseRef
+ = _serializerMap.get(cl);
+
+ UnsafeSerializer base = baseRef != null ? baseRef.get() : null;
+
+ if (base == null) {
+ if (cl.isAnnotationPresent(HessianUnshared.class))
+ base = new UnsafeUnsharedSerializer(cl);
+ else
+ base = new UnsafeSerializer(cl);
+
+ baseRef = new SoftReference<UnsafeSerializer>(base);
+ _serializerMap.put(cl, baseRef);
+ }
+
+ return base;
+ }
+ }
+
+ private static FieldSerializer getFieldSerializer(Field field) {
+ Class<?> type = field.getType();
+
+ if (boolean.class.equals(type)) {
+ return new BooleanFieldSerializer(field);
+ } else if (byte.class.equals(type)) {
+ return new ByteFieldSerializer(field);
+ } else if (char.class.equals(type)) {
+ return new CharFieldSerializer(field);
+ } else if (short.class.equals(type)) {
+ return new ShortFieldSerializer(field);
+ } else if (int.class.equals(type)) {
+ return new IntFieldSerializer(field);
+ } else if (long.class.equals(type)) {
+ return new LongFieldSerializer(field);
+ } else if (double.class.equals(type)) {
+ return new DoubleFieldSerializer(field);
+ } else if (float.class.equals(type)) {
+ return new FloatFieldSerializer(field);
+ } else if (String.class.equals(type)) {
+ return new StringFieldSerializer(field);
+ } else if (java.util.Date.class.equals(type)
+ || java.sql.Date.class.equals(type)
+ || java.sql.Timestamp.class.equals(type)
+ || java.sql.Time.class.equals(type)) {
+ return new DateFieldSerializer(field);
+ } else
+ return new ObjectFieldSerializer(field);
+ }
+
+ protected void introspect(Class<?> cl) {
+ ArrayList<Field> primitiveFields = new ArrayList<Field>();
+ ArrayList<Field> compoundFields = new ArrayList<Field>();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field[] fields = cl.getDeclaredFields();
+
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers())) {
+ continue;
+ }
+
+ /*
+ // XXX: could parameterize the handler to only deal with public
+ field.setAccessible(true);
+ */
+
+ if (field.getType().isPrimitive()
+ || (field.getType().getName().startsWith("java.lang.")
+ && !field.getType().equals(Object.class))) {
+ primitiveFields.add(field);
+ } else {
+ compoundFields.add(field);
+ }
+ }
+ }
+
+ ArrayList<Field> fields = new ArrayList<Field>();
+ fields.addAll(primitiveFields);
+ fields.addAll(compoundFields);
+ Collections.reverse(fields);
+
+ _fields = new Field[fields.size()];
+ fields.toArray(_fields);
+
+ _fieldSerializers = new FieldSerializer[_fields.length];
+
+ for (int i = 0; i < _fields.length; i++) {
+ _fieldSerializers[i] = getFieldSerializer(_fields[i]);
+ }
+ }
+
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ Class<?> cl = obj.getClass();
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref >= 0) {
+ writeInstance(obj, out);
+ } else if (ref == -1) {
+ writeDefinition20(out);
+ out.writeObjectBegin(cl.getName());
+ writeInstance(obj, out);
+ } else {
+ writeObject10(obj, out);
+ }
+ }
+
+ protected void writeObject10(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ out.writeString(field.getName());
+
+ _fieldSerializers[i].serialize(out, obj);
+ }
+
+ out.writeMapEnd();
+ }
+
+ private void writeDefinition20(AbstractHessianOutput out)
+ throws IOException {
+ out.writeClassFieldLength(_fields.length);
+
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ out.writeString(field.getName());
+ }
+ }
+
+ final public void writeInstance(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ try {
+ FieldSerializer[] fieldSerializers = _fieldSerializers;
+ int length = fieldSerializers.length;
+
+ for (int i = 0; i < length; i++) {
+ fieldSerializers[i].serialize(out, obj);
+ }
+ } catch (RuntimeException e) {
+ throw new RuntimeException(e.getMessage() + "\n class: "
+ + obj.getClass().getName(),
+ e);
+ } catch (IOException e) {
+ throw new IOExceptionWrapper(e.getMessage() + "\n class: "
+ + obj.getClass().getName(),
+ e);
+ }
+ }
+
+ abstract static class FieldSerializer {
+ abstract void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException;
+ }
+
+ final static class ObjectFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ ObjectFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ @Override
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ try {
+ Object value = _unsafe.getObject(obj, _offset);
+
+ out.writeObject(value);
+ } catch (RuntimeException e) {
+ throw new RuntimeException(e.getMessage() + "\n field: "
+ + _field.getDeclaringClass().getName()
+ + '.' + _field.getName(),
+ e);
+ } catch (IOException e) {
+ throw new IOExceptionWrapper(e.getMessage() + "\n field: "
+ + _field.getDeclaringClass().getName()
+ + '.' + _field.getName(),
+ e);
+ }
+ }
+ }
+
+ final static class BooleanFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ BooleanFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ boolean value = _unsafe.getBoolean(obj, _offset);
+
+ out.writeBoolean(value);
+ }
+ }
+
+ final static class ByteFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ ByteFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ int value = _unsafe.getByte(obj, _offset);
+
+ out.writeInt(value);
+ }
+ }
+
+ final static class CharFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ CharFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ char value = _unsafe.getChar(obj, _offset);
+
+ out.writeString(String.valueOf(value));
+ }
+ }
+
+ final static class ShortFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ ShortFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ int value = _unsafe.getShort(obj, _offset);
+
+ out.writeInt(value);
+ }
+ }
+
+ final static class IntFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ IntFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ int value = _unsafe.getInt(obj, _offset);
+
+ out.writeInt(value);
+ }
+ }
+
+ final static class LongFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ LongFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ long value = _unsafe.getLong(obj, _offset);
+
+ out.writeLong(value);
+ }
+ }
+
+ final static class FloatFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ FloatFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ double value = _unsafe.getFloat(obj, _offset);
+
+ out.writeDouble(value);
+ }
+ }
+
+ final static class DoubleFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ DoubleFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ double value = _unsafe.getDouble(obj, _offset);
+
+ out.writeDouble(value);
+ }
+ }
+
+ final static class StringFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ StringFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ @Override
+ final void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ String value = (String) _unsafe.getObject(obj, _offset);
+
+ out.writeString(value);
+ }
+ }
+
+ final static class DateFieldSerializer extends FieldSerializer {
+ private final Field _field;
+ private final long _offset;
+
+ DateFieldSerializer(Field field) {
+ _field = field;
+ _offset = _unsafe.objectFieldOffset(field);
+
+ if (_offset == Unsafe.INVALID_FIELD_OFFSET)
+ throw new IllegalStateException();
+ }
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj)
+ throws IOException {
+ java.util.Date value
+ = (java.util.Date) _unsafe.getObject(obj, _offset);
+
+ if (value == null)
+ out.writeNull();
+ else
+ out.writeUTCDate(value.getTime());
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeUnsharedSerializer.java
similarity index 75%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeUnsharedSerializer.java
index 72a9822..1710b6d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/UnsafeUnsharedSerializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -49,17 +49,28 @@
package com.alibaba.com.caucho.hessian.io;
import java.io.IOException;
+import java.util.logging.Logger;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object for known object types.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class UnsafeUnsharedSerializer extends UnsafeSerializer {
+ private static final Logger log
+ = Logger.getLogger(UnsafeUnsharedSerializer.class.getName());
+
+ public UnsafeUnsharedSerializer(Class<?> cl) {
+ super(cl);
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ boolean oldUnshared = out.setUnshared(true);
+
+ try {
+ super.writeObject(obj, out);
+ } finally {
+ out.setUnshared(oldUnshared);
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java
index af548ac..ea99666 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/ValueDeserializer.java
@@ -54,7 +54,6 @@
* Deserializing a string valued object
*/
abstract public class ValueDeserializer extends AbstractDeserializer {
- @Override
public Object readMap(AbstractHessianInput in)
throws IOException {
String initValue = null;
@@ -73,7 +72,6 @@
return create(initValue);
}
- @Override
public Object readObject(AbstractHessianInput in, String[] fieldNames)
throws IOException {
String initValue = null;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/WriteReplaceSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/WriteReplaceSerializer.java
new file mode 100644
index 0000000..9e3c26a
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/WriteReplaceSerializer.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.io;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class WriteReplaceSerializer extends AbstractSerializer {
+ private static final Logger log
+ = Logger.getLogger(WriteReplaceSerializer.class.getName());
+
+ private Object _writeReplaceFactory;
+ private Method _writeReplace;
+ private Serializer _baseSerializer;
+
+ public WriteReplaceSerializer(Class<?> cl,
+ ClassLoader loader,
+ Serializer baseSerializer) {
+ introspectWriteReplace(cl, loader);
+
+ _baseSerializer = baseSerializer;
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected static Method getWriteReplace(Class<?> cl, Class<?> param) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ for (Method method : cl.getDeclaredMethods()) {
+ if (method.getName().equals("writeReplace")
+ && method.getParameterTypes().length == 1
+ && param.equals(method.getParameterTypes()[0]))
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected static Method getWriteReplace(Class<?> cl) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("writeReplace") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ private void introspectWriteReplace(Class<?> cl, ClassLoader loader) {
+ try {
+ String className = cl.getName() + "HessianSerializer";
+
+ Class<?> serializerClass = Class.forName(className, false, loader);
+
+ Object serializerObject = serializerClass.newInstance();
+
+ Method writeReplace = getWriteReplace(serializerClass, cl);
+
+ if (writeReplace != null) {
+ _writeReplaceFactory = serializerObject;
+ _writeReplace = writeReplace;
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (Exception e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ _writeReplace = getWriteReplace(cl);
+ if (_writeReplace != null)
+ _writeReplace.setAccessible(true);
+ }
+
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ int ref = out.getRef(obj);
+
+ if (ref >= 0) {
+ out.writeRef(ref);
+
+ return;
+ }
+
+ try {
+ Object repl;
+
+ repl = writeReplace(obj);
+
+ if (obj == repl) {
+ if (log.isLoggable(Level.FINE)) {
+ log.fine(this + ": Hessian writeReplace error. The writeReplace method (" + _writeReplace + ") must not return the same object");
+ }
+
+ _baseSerializer.writeObject(obj, out);
+
+ return;
+ }
+
+ out.writeObject(repl);
+
+ out.replaceRef(repl, obj);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected Object writeReplace(Object obj) {
+ try {
+ if (_writeReplaceFactory != null)
+ return _writeReplace.invoke(_writeReplaceFactory, obj);
+ else
+ return _writeReplace.invoke(obj);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getCause());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/DurationSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/DurationSerializer.java
index 5cd0498..ba30a6e
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/DurationSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class DurationSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new DurationHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/InstantSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/InstantSerializer.java
index 5cd0498..d31c485
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/InstantSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class InstantSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new InstantHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalDateSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalDateSerializer.java
index 5cd0498..6956d9d
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalDateSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class LocalDateSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new LocalDateHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalDateTimeSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalDateTimeSerializer.java
index 5cd0498..3c67e8f
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalDateTimeSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class LocalDateTimeSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new LocalDateTimeHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalTimeSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalTimeSerializer.java
index 5cd0498..226a0e3
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/LocalTimeSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class LocalTimeSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new LocalTimeHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/MonthDaySerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/MonthDaySerializer.java
index 5cd0498..708cd04
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/MonthDaySerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class MonthDaySerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new MonthDayHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/OffsetDateTimeSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/OffsetDateTimeSerializer.java
index 5cd0498..63726d6
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/OffsetDateTimeSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class OffsetDateTimeSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new OffsetDateTimeHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/OffsetTimeSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/OffsetTimeSerializer.java
index 5cd0498..2531732
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/OffsetTimeSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class OffsetTimeSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new OffsetTimeHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/PeriodSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/PeriodSerializer.java
index 5cd0498..b7edfec
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/PeriodSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class PeriodSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new PeriodHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/YearMonthSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/YearMonthSerializer.java
index 5cd0498..dc12092
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/YearMonthSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class YearMonthSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new YearMonthHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/YearSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/YearSerializer.java
index 5cd0498..2973fc9
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/YearSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class YearSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new YearHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneIdSerializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneIdSerializer.java
index 7217be4..18a03d3 100755
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneIdSerializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneIdSerializer.java
@@ -17,6 +17,7 @@
package com.alibaba.com.caucho.hessian.io.java8;
+
import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneOffsetSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneOffsetSerializer.java
index 5cd0498..72a28c2
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZoneOffsetSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class ZoneOffsetSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new ZoneOffsetHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZonedDateTimeSerializer.java
old mode 100644
new mode 100755
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
copy to src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZonedDateTimeSerializer.java
index 5cd0498..32dd460
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/io/java8/ZonedDateTimeSerializer.java
@@ -15,18 +15,23 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian.io.java8;
-import java.math.BigInteger;
-public class BigIntegerDeserializer extends JavaDeserializer {
+import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
- public BigIntegerDeserializer() {
- super(BigInteger.class);
- }
+import java.io.IOException;
+
+public class ZonedDateTimeSerializer<T> extends AbstractSerializer {
@Override
- protected Object instantiate() throws Exception {
- return new BigInteger("0");
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ return;
+ }
+
+ out.writeObject(new ZonedDateTimeHandle(obj));
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/util/HessianFreeList.java b/src/main/java/com/alibaba/com/caucho/hessian/util/HessianFreeList.java
new file mode 100644
index 0000000..245dbb6
--- /dev/null
+++ b/src/main/java/com/alibaba/com/caucho/hessian/util/HessianFreeList.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReferenceArray;
+
+/**
+ * FreeList provides a simple class to manage free objects. This is useful
+ * for large data structures that otherwise would gobble up huge GC time.
+ *
+ * <p>The free list is bounded. Freeing an object when the list is full will
+ * do nothing.
+ */
+public final class HessianFreeList<T> {
+ private final AtomicReferenceArray<T> _freeStack;
+ private final AtomicInteger _top = new AtomicInteger();
+
+ /**
+ * Create a new free list.
+ *
+ * @param initialSize maximum number of free objects to store.
+ */
+ public HessianFreeList(int size) {
+ _freeStack = new AtomicReferenceArray(size);
+ }
+
+ /**
+ * Try to get an object from the free list. Returns null if the free list
+ * is empty.
+ *
+ * @return the new object or null.
+ */
+ public T allocate() {
+ int top = _top.get();
+
+ if (top > 0 && _top.compareAndSet(top, top - 1))
+ return _freeStack.getAndSet(top - 1, null);
+ else
+ return null;
+ }
+
+ /**
+ * Frees the object. If the free list is full, the object will be garbage
+ * collected.
+ *
+ * @param obj the object to be freed.
+ */
+ public boolean free(T obj) {
+ int top = _top.get();
+
+ if (top < _freeStack.length()) {
+ boolean isFree = _freeStack.compareAndSet(top, null, obj);
+
+ _top.compareAndSet(top, top + 1);
+
+ return isFree;
+ } else
+ return false;
+ }
+
+ public boolean allowFree(T obj) {
+ return _top.get() < _freeStack.length();
+ }
+
+ /**
+ * Frees the object. If the free list is full, the object will be garbage
+ * collected.
+ *
+ * @param obj the object to be freed.
+ */
+ public void freeCareful(T obj) {
+ if (checkDuplicate(obj))
+ throw new IllegalStateException("tried to free object twice");
+
+ free(obj);
+ }
+
+ /**
+ * Debugging to see if the object has already been freed.
+ */
+ public boolean checkDuplicate(T obj) {
+ int top = _top.get();
+
+ for (int i = top - 1; i >= 0; i--) {
+ if (_freeStack.get(i) == obj)
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java b/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java
index afa3a9f..b604d5f 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java
@@ -51,7 +51,7 @@
/**
* The IntMap provides a simple hashmap from keys to integers. The API is
* an abbreviation of the HashMap collection API.
- * <p>
+ *
* <p>The convenience of IntMap is avoiding all the silly wrapping of
* integers.
*/
@@ -61,32 +61,69 @@
* it's impossible to distinguish between the two.
*/
public final static int NULL = 0xdeadbeef; // Integer.MIN_VALUE + 1;
-
- private static final Object DELETED = new Object();
-
+ public static final int[] PRIMES =
+ {
+ 1, /* 1<< 0 = 1 */
+ 2, /* 1<< 1 = 2 */
+ 3, /* 1<< 2 = 4 */
+ 7, /* 1<< 3 = 8 */
+ 13, /* 1<< 4 = 16 */
+ 31, /* 1<< 5 = 32 */
+ 61, /* 1<< 6 = 64 */
+ 127, /* 1<< 7 = 128 */
+ 251, /* 1<< 8 = 256 */
+ 509, /* 1<< 9 = 512 */
+ 1021, /* 1<<10 = 1024 */
+ 2039, /* 1<<11 = 2048 */
+ 4093, /* 1<<12 = 4096 */
+ 8191, /* 1<<13 = 8192 */
+ 16381, /* 1<<14 = 16384 */
+ 32749, /* 1<<15 = 32768 */
+ 65521, /* 1<<16 = 65536 */
+ 131071, /* 1<<17 = 131072 */
+ 262139, /* 1<<18 = 262144 */
+ 524287, /* 1<<19 = 524288 */
+ 1048573, /* 1<<20 = 1048576 */
+ 2097143, /* 1<<21 = 2097152 */
+ 4194301, /* 1<<22 = 4194304 */
+ 8388593, /* 1<<23 = 8388608 */
+ 16777213, /* 1<<24 = 16777216 */
+ 33554393, /* 1<<25 = 33554432 */
+ 67108859, /* 1<<26 = 67108864 */
+ 134217689, /* 1<<27 = 134217728 */
+ 268435399, /* 1<<28 = 268435456 */
+ };
private Object[] _keys;
private int[] _values;
-
private int _size;
- private int _mask;
+ private int _prime;
/**
* Create a new IntMap. Default size is 16.
*/
- public IdentityIntMap() {
- _keys = new Object[256];
- _values = new int[256];
+ public IdentityIntMap(int capacity) {
+ _keys = new Object[capacity];
+ _values = new int[capacity];
- _mask = _keys.length - 1;
+ _prime = getBiggestPrime(_keys.length);
_size = 0;
}
+ public static int getBiggestPrime(int value) {
+ for (int i = PRIMES.length - 1; i >= 0; i--) {
+ if (PRIMES[i] <= value)
+ return PRIMES[i];
+ }
+
+ return 2;
+ }
+
/**
* Clear the hashmap.
*/
public void clear() {
- Object[] keys = _keys;
- int[] values = _values;
+ final Object[] keys = _keys;
+ final int[] values = _values;
for (int i = keys.length - 1; i >= 0; i--) {
keys[i] = null;
@@ -99,18 +136,19 @@
/**
* Returns the current number of entries in the map.
*/
- public int size() {
+ public final int size() {
return _size;
}
/**
* Puts a new value in the property table with the appropriate flags
*/
- public int get(Object key) {
- int mask = _mask;
- int hash = System.identityHashCode(key) % mask & mask;
+ public final int get(Object key) {
+ int prime = _prime;
+ int hash = System.identityHashCode(key) % prime;
+ // int hash = key.hashCode() & mask;
- Object[] keys = _keys;
+ final Object[] keys = _keys;
while (true) {
Object mapKey = keys[hash];
@@ -120,58 +158,24 @@
else if (mapKey == key)
return _values[hash];
- hash = (hash + 1) % mask;
+ hash = (hash + 1) % prime;
}
}
/**
- * Expands the property table
- */
- private void resize(int newSize) {
- Object[] newKeys = new Object[newSize];
- int[] newValues = new int[newSize];
-
- int mask = _mask = newKeys.length - 1;
-
- Object[] keys = _keys;
- int values[] = _values;
-
- for (int i = keys.length - 1; i >= 0; i--) {
- Object key = keys[i];
-
- if (key == null || key == DELETED)
- continue;
-
- int hash = System.identityHashCode(key) % mask & mask;
-
- while (true) {
- if (newKeys[hash] == null) {
- newKeys[hash] = key;
- newValues[hash] = values[i];
- break;
- }
-
- hash = (hash + 1) % mask;
- }
- }
-
- _keys = newKeys;
- _values = newValues;
- }
-
- /**
* Puts a new value in the property table with the appropriate flags
*/
- public int put(Object key, int value) {
- int mask = _mask;
- int hash = System.identityHashCode(key) % mask & mask;
+ public final int put(Object key, int value, boolean isReplace) {
+ int prime = _prime;
+ int hash = Math.abs(System.identityHashCode(key) % prime);
+ // int hash = key.hashCode() % prime;
Object[] keys = _keys;
while (true) {
Object testKey = keys[hash];
- if (testKey == null || testKey == DELETED) {
+ if (testKey == null) {
keys[hash] = key;
_values[hash] = value;
@@ -180,54 +184,67 @@
if (keys.length <= 4 * _size)
resize(4 * keys.length);
- return NULL;
+ return value;
} else if (key != testKey) {
- hash = (hash + 1) % mask;
+ hash = (hash + 1) % prime;
continue;
- } else {
+ } else if (isReplace) {
int old = _values[hash];
_values[hash] = value;
return old;
+ } else {
+ return _values[hash];
}
}
}
/**
- * Deletes the entry. Returns true if successful.
+ * Removes a value in the property table.
*/
- public int remove(Object key) {
- int mask = _mask;
- int hash = System.identityHashCode(key) % mask & mask;
-
- while (true) {
- Object mapKey = _keys[hash];
-
- if (mapKey == null)
- return NULL;
- else if (mapKey == key) {
- _keys[hash] = DELETED;
-
- _size--;
-
- return _values[hash];
- }
-
- hash = (hash + 1) % mask;
+ public final void remove(Object key) {
+ if (put(key, NULL, true) != NULL) {
+ _size--;
}
}
- @Override
+ /**
+ * Expands the property table
+ */
+ private void resize(int newSize) {
+ Object[] keys = _keys;
+ int values[] = _values;
+
+ _keys = new Object[newSize];
+ _values = new int[newSize];
+ _size = 0;
+
+ _prime = getBiggestPrime(_keys.length);
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ Object key = keys[i];
+ int value = values[i];
+
+ if (key != null && value != NULL) {
+ put(key, value, true);
+ }
+ }
+ }
+
+ protected int hashCode(Object value) {
+ return System.identityHashCode(value);
+ }
+
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("IntMap[");
boolean isFirst = true;
- for (int i = 0; i <= _mask; i++) {
- if (_keys[i] != null && _keys[i] != DELETED) {
+ for (int i = 0; i <= _keys.length; i++) {
+ if (_keys[i] != null) {
if (!isFirst)
sbuf.append(", ");
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java b/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java
index 8711570..5fbdb6c 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java
+++ b/src/main/java/com/alibaba/com/caucho/hessian/util/IntMap.java
@@ -51,7 +51,7 @@
/**
* The IntMap provides a simple hashmap from keys to integers. The API is
* an abbreviation of the HashMap collection API.
- * <p>
+ *
* <p>The convenience of IntMap is avoiding all the silly wrapping of
* integers.
*/
@@ -61,32 +61,71 @@
* it's impossible to distinguish between the two.
*/
public final static int NULL = 0xdeadbeef; // Integer.MIN_VALUE + 1;
-
- private static final Object DELETED = new Object();
-
+ public static final int[] PRIMES =
+ {
+ 1, /* 1<< 0 = 1 */
+ 2, /* 1<< 1 = 2 */
+ 3, /* 1<< 2 = 4 */
+ 7, /* 1<< 3 = 8 */
+ 13, /* 1<< 4 = 16 */
+ 31, /* 1<< 5 = 32 */
+ 61, /* 1<< 6 = 64 */
+ 127, /* 1<< 7 = 128 */
+ 251, /* 1<< 8 = 256 */
+ 509, /* 1<< 9 = 512 */
+ 1021, /* 1<<10 = 1024 */
+ 2039, /* 1<<11 = 2048 */
+ 4093, /* 1<<12 = 4096 */
+ 8191, /* 1<<13 = 8192 */
+ 16381, /* 1<<14 = 16384 */
+ 32749, /* 1<<15 = 32768 */
+ 65521, /* 1<<16 = 65536 */
+ 131071, /* 1<<17 = 131072 */
+ 262139, /* 1<<18 = 262144 */
+ 524287, /* 1<<19 = 524288 */
+ 1048573, /* 1<<20 = 1048576 */
+ 2097143, /* 1<<21 = 2097152 */
+ 4194301, /* 1<<22 = 4194304 */
+ 8388593, /* 1<<23 = 8388608 */
+ 16777213, /* 1<<24 = 16777216 */
+ 33554393, /* 1<<25 = 33554432 */
+ 67108859, /* 1<<26 = 67108864 */
+ 134217689, /* 1<<27 = 134217728 */
+ 268435399, /* 1<<28 = 268435456 */
+ };
private Object[] _keys;
private int[] _values;
-
private int _size;
- private int _mask;
+ private int _prime;
/**
* Create a new IntMap. Default size is 16.
*/
public IntMap() {
- _keys = new Object[256];
- _values = new int[256];
+ int capacity = 1024;
- _mask = _keys.length - 1;
+ _keys = new Object[capacity];
+ _values = new int[capacity];
+
+ _prime = getBiggestPrime(_keys.length);
_size = 0;
}
+ public static int getBiggestPrime(int value) {
+ for (int i = PRIMES.length - 1; i >= 0; i--) {
+ if (PRIMES[i] <= value)
+ return PRIMES[i];
+ }
+
+ return 2;
+ }
+
/**
* Clear the hashmap.
*/
public void clear() {
- Object[] keys = _keys;
- int[] values = _values;
+ final Object[] keys = _keys;
+ final int[] values = _values;
for (int i = keys.length - 1; i >= 0; i--) {
keys[i] = null;
@@ -99,79 +138,46 @@
/**
* Returns the current number of entries in the map.
*/
- public int size() {
+ public final int size() {
return _size;
}
/**
* Puts a new value in the property table with the appropriate flags
*/
- public int get(Object key) {
- int mask = _mask;
- int hash = key.hashCode() % mask & mask;
+ public final int get(Object key) {
+ int prime = _prime;
+ int hash = hashCode(key) % prime;
+ // int hash = key.hashCode() & mask;
- Object[] keys = _keys;
+ final Object[] keys = _keys;
while (true) {
Object mapKey = keys[hash];
if (mapKey == null)
return NULL;
- else if (mapKey == key || mapKey.equals(key))
+ else if (mapKey == key)
return _values[hash];
- hash = (hash + 1) % mask;
+ hash = (hash + 1) % prime;
}
}
/**
- * Expands the property table
- */
- private void resize(int newSize) {
- Object[] newKeys = new Object[newSize];
- int[] newValues = new int[newSize];
-
- int mask = _mask = newKeys.length - 1;
-
- Object[] keys = _keys;
- int values[] = _values;
-
- for (int i = keys.length - 1; i >= 0; i--) {
- Object key = keys[i];
-
- if (key == null || key == DELETED)
- continue;
-
- int hash = key.hashCode() % mask & mask;
-
- while (true) {
- if (newKeys[hash] == null) {
- newKeys[hash] = key;
- newValues[hash] = values[i];
- break;
- }
-
- hash = (hash + 1) % mask;
- }
- }
-
- _keys = newKeys;
- _values = newValues;
- }
-
- /**
* Puts a new value in the property table with the appropriate flags
*/
- public int put(Object key, int value) {
- int mask = _mask;
- int hash = key.hashCode() % mask & mask;
+ public final int put(Object key, int value, boolean isReplace) {
+ int prime = _prime;
+ int hash = hashCode(key) % prime;
+ // int hash = key.hashCode() % prime;
Object[] keys = _keys;
while (true) {
Object testKey = keys[hash];
- if (testKey == null || testKey == DELETED) {
+ if (testKey == null) {
keys[hash] = key;
_values[hash] = value;
@@ -181,53 +187,56 @@
resize(4 * keys.length);
return NULL;
- } else if (key != testKey && !key.equals(testKey)) {
- hash = (hash + 1) % mask;
+ } else if (key != testKey) {
+ hash = (hash + 1) % prime;
continue;
- } else {
+ } else if (isReplace) {
int old = _values[hash];
_values[hash] = value;
return old;
+ } else {
+ return _values[hash];
}
}
}
/**
- * Deletes the entry. Returns true if successful.
+ * Expands the property table
*/
- public int remove(Object key) {
- int mask = _mask;
- int hash = key.hashCode() % mask & mask;
+ private void resize(int newSize) {
+ Object[] keys = _keys;
+ int values[] = _values;
- while (true) {
- Object mapKey = _keys[hash];
+ _keys = new Object[newSize];
+ _values = new int[newSize];
+ _size = 0;
- if (mapKey == null)
- return NULL;
- else if (mapKey == key) {
- _keys[hash] = DELETED;
+ _prime = getBiggestPrime(_keys.length);
- _size--;
+ for (int i = keys.length - 1; i >= 0; i--) {
+ Object key = keys[i];
- return _values[hash];
+ if (key != null) {
+ put(key, values[i], true);
}
-
- hash = (hash + 1) % mask;
}
}
- @Override
+ protected int hashCode(Object value) {
+ return value.hashCode();
+ }
+
public String toString() {
StringBuffer sbuf = new StringBuffer();
sbuf.append("IntMap[");
boolean isFirst = true;
- for (int i = 0; i <= _mask; i++) {
- if (_keys[i] != null && _keys[i] != DELETED) {
+ for (int i = 0; i <= _keys.length; i++) {
+ if (_keys[i] != null) {
if (!isFirst)
sbuf.append(", ");
diff --git a/src/main/resources/META-INF/dubbo/hessian/deserializers b/src/main/resources/META-INF/dubbo/hessian/deserializers
new file mode 100644
index 0000000..ee6b6b1
--- /dev/null
+++ b/src/main/resources/META-INF/dubbo/hessian/deserializers
@@ -0,0 +1,3 @@
+java.io.File=com.alibaba.com.caucho.hessian.io.FileDeserializer
+java.math.BigDecimal=com.alibaba.com.caucho.hessian.io.BigDecimalDeserializer
+javax.management.ObjectName=com.alibaba.com.caucho.hessian.io.ObjectNameDeserializer
diff --git a/src/main/resources/META-INF/dubbo/hessian/serializers b/src/main/resources/META-INF/dubbo/hessian/serializers
new file mode 100644
index 0000000..3423280
--- /dev/null
+++ b/src/main/resources/META-INF/dubbo/hessian/serializers
@@ -0,0 +1,18 @@
+java.io.File=com.alibaba.com.caucho.hessian.io.StringValueSerializer
+java.math.BigDecimal=com.alibaba.com.caucho.hessian.io.StringValueSerializer
+java.util.Locale=com.alibaba.com.caucho.hessian.io.LocaleSerializer
+javax.management.ObjectName=com.alibaba.com.caucho.hessian.io.StringValueSerializer
+java.time.Duration=com.alibaba.com.caucho.hessian.io.java8.DurationSerializer
+java.time.Instant=com.alibaba.com.caucho.hessian.io.java8.InstantSerializer
+java.time.LocalDate=com.alibaba.com.caucho.hessian.io.java8.LocalDateSerializer
+java.time.LocalDateTime=com.alibaba.com.caucho.hessian.io.java8.LocalDateTimeSerializer
+java.time.LocalTime=com.alibaba.com.caucho.hessian.io.java8.LocalTimeSerializer
+java.time.MonthDay=com.alibaba.com.caucho.hessian.io.java8.MonthDaySerializer
+java.time.OffsetDateTime=com.alibaba.com.caucho.hessian.io.java8.OffsetDateTimeSerializer
+java.time.OffsetTime=com.alibaba.com.caucho.hessian.io.java8.OffsetTimeSerializer
+java.time.Period=com.alibaba.com.caucho.hessian.io.java8.PeriodSerializer
+java.time.Year=com.alibaba.com.caucho.hessian.io.java8.YearSerializer
+java.time.YearMonth=com.alibaba.com.caucho.hessian.io.java8.YearMonthSerializer
+java.time.ZonedDateTime=com.alibaba.com.caucho.hessian.io.java8.ZonedDateTimeSerializer
+java.time.ZoneId=com.alibaba.com.caucho.hessian.io.java8.ZoneIdSerializer
+java.time.ZoneOffset=com.alibaba.com.caucho.hessian.io.java8.ZoneOffsetSerializer
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/BitSetSerializerTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/BitSetSerializerTest.java
index 94a5fd9..64e97a0 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/BitSetSerializerTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/BitSetSerializerTest.java
@@ -43,6 +43,5 @@
private void assertBitSet(BitSet bitSet) throws IOException {
TestCase.assertEquals(bitSet, baseHessian2Serialize(bitSet));
- TestCase.assertEquals(bitSet, baseHessianSerialize(bitSet));
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java
index 75aa608..09970e6 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/CollectionSerializerTest.java
@@ -38,7 +38,7 @@
set.add(1111);
set.add(2222);
- Set deserialize = baseHessianSerialize(set);
+ Set deserialize = baseHessian2Serialize(set);
Assert.assertTrue(deserialize.equals(set));
}
@@ -89,7 +89,7 @@
list.add(1111);
list.add(2222);
- List deserialize = baseHessianSerialize(list);
+ List deserialize = baseHessian2Serialize(list);
Assert.assertTrue(deserialize.equals(list));
}
@@ -101,7 +101,7 @@
vector.add(1111);
vector.add(2222);
- List deserialize = baseHessianSerialize(vector);
+ List deserialize = baseHessian2Serialize(vector);
Assert.assertTrue(deserialize.equals(vector));
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian1StringShortTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian1StringShortTest.java
deleted file mode 100644
index c3ead15..0000000
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian1StringShortTest.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.alibaba.com.caucho.hessian.io;
-
-import com.alibaba.com.caucho.hessian.io.base.SerializeTestBase;
-import com.alibaba.com.caucho.hessian.io.beans.Hessian2StringShortType;
-import com.alibaba.com.caucho.hessian.io.beans.PersonType;
-
-import org.junit.Test;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
-
-public class Hessian1StringShortTest extends SerializeTestBase {
-
- @Test
- public void serialize_string_short_map_then_deserialize() throws Exception {
-
- Hessian2StringShortType stringShort = new Hessian2StringShortType();
- Map<String, Short> stringShortMap = new HashMap<String, Short>();
- stringShortMap.put("first", (short)0);
- stringShortMap.put("last", (short)60);
- stringShort.stringShortMap = stringShortMap;
-
- Hessian2StringShortType deserialize = baseHessianSerialize(stringShort);
- assertTrue(deserialize.stringShortMap != null);
- assertTrue(deserialize.stringShortMap.size() == 2);
- assertTrue(deserialize.stringShortMap.get("last") instanceof Short);
- assertEquals(Short.valueOf((short)0), deserialize.stringShortMap.get("first"));
- assertEquals(Short.valueOf((short)60), deserialize.stringShortMap.get("last"));
- }
-
- @Test
- public void serialize_string_byte_map_then_deserialize() throws Exception {
-
- Hessian2StringShortType stringShort = new Hessian2StringShortType();
- Map<String, Byte> stringByteMap = new HashMap<String, Byte>();
- stringByteMap.put("first", (byte)0);
- stringByteMap.put("last", (byte)60);
- stringShort.stringByteMap = stringByteMap;
-
- Hessian2StringShortType deserialize = baseHessianSerialize(stringShort);
- assertTrue(deserialize.stringByteMap != null);
- assertTrue(deserialize.stringByteMap.size() == 2);
- assertTrue(deserialize.stringByteMap.get("last") instanceof Byte);
- assertEquals(Byte.valueOf((byte)0), deserialize.stringByteMap.get("first"));
- assertEquals(Byte.valueOf((byte) 60), deserialize.stringByteMap.get("last"));
- }
-
- @Test
- public void serialize_map_then_deserialize() throws Exception {
-
- Map<String, Short> stringShortMap = new HashMap<String, Short>();
- stringShortMap.put("first", (short)0);
- stringShortMap.put("last", (short)60);
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- HessianOutput out = new HessianOutput(bout);
-
- out.writeObject(stringShortMap);
- out.flush();
-
- ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
- HessianInput input = new HessianInput(bin);
- Map deserialize = (Map) input.readObject(HashMap.class, String.class, Short.class);
- assertTrue(deserialize != null);
- assertTrue(deserialize.size() == 2);
- assertTrue(deserialize.get("last") instanceof Short);
- assertEquals(Short.valueOf((short)0), deserialize.get("first"));
- assertEquals(Short.valueOf((short)60), deserialize.get("last"));
- }
-
- @Test
- public void serialize_map_then_deserialize0() throws Exception {
-
- Map<String, Short> stringShortMap = new HashMap<String, Short>();
- stringShortMap.put("first", (short)0);
- stringShortMap.put("last", (short)60);
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- HessianOutput out = new HessianOutput(bout);
-
- out.writeObject(stringShortMap);
- out.flush();
-
- ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
- HessianInput input = new HessianInput(bin);
- List<Class<?>> keyValueType = new ArrayList<Class<?>>();
- keyValueType.add(String.class);
- keyValueType.add(short.class);
-
- Map deserialize = (Map) input.readObject(keyValueType);
- assertTrue(deserialize != null);
- assertTrue(deserialize.size() == 2);
- assertTrue(deserialize.get("last") instanceof Short);
- assertEquals(Short.valueOf((short)0), deserialize.get("first"));
- assertEquals(Short.valueOf((short)60), deserialize.get("last"));
- }
-
- @Test
- public void serialize_string_person_map_then_deserialize() throws Exception {
-
- Hessian2StringShortType stringShort = new Hessian2StringShortType();
- Map<String, PersonType> stringPersonTypeMap = new HashMap<String, PersonType>();
- stringPersonTypeMap.put("first", new PersonType(
- "jason.shang", 26, (double) 0.1, (short)1, (byte)2, Arrays.asList((short)1,(short)1)
- ));
- stringPersonTypeMap.put("last", new PersonType(
- "jason.shang2", 52, (double) 0.2, (short)2, (byte)4, Arrays.asList((short)2,(short)2)
- ));
- stringShort.stringPersonTypeMap = stringPersonTypeMap;
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- HessianOutput out = new HessianOutput(bout);
-
- out.writeObject(stringShort);
- out.flush();
-
- ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
- HessianInput input = new HessianInput(bin);
-
- Hessian2StringShortType deserialize = (Hessian2StringShortType) input.readObject();
- assertTrue(deserialize.stringPersonTypeMap != null);
- assertTrue(deserialize.stringPersonTypeMap.size() == 2);
- assertTrue(deserialize.stringPersonTypeMap.get("last") instanceof PersonType);
-
-
- assertEquals(new PersonType(
- "jason.shang", 26, (double) 0.1, (short)1, (byte)2, Arrays.asList((short)1,(short)1)
- ), deserialize.stringPersonTypeMap.get("first"));
-
- assertEquals(new PersonType(
- "jason.shang2", 52, (double) 0.2, (short)2, (byte)4, Arrays.asList((short)2,(short)2)
- ), deserialize.stringPersonTypeMap.get("last"));
-
- }
-
- @Test
- public void serialize_list_then_deserialize() throws Exception {
-
- List<Short> shortList = new ArrayList<Short>();
- shortList.add((short)0);
- shortList.add((short)60);
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- HessianOutput out = new HessianOutput(bout);
-
- out.writeObject(shortList);
- out.flush();
-
- ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
- HessianInput input = new HessianInput(bin);
- List<Short> deserialize = (List) input.readObject(ArrayList.class, Short.class);
- assertTrue(deserialize != null);
- assertTrue(deserialize.size() == 2);
- assertTrue(deserialize.get(1) instanceof Short);
- assertEquals(Short.valueOf((short)0), deserialize.get(0));
- assertEquals(Short.valueOf((short)60), deserialize.get(1));
- }
-
- @Test
- public void serialize_list_then_deserialize0() throws Exception {
-
- List<Short> shortList = new ArrayList<Short>();
- shortList.add((short)0);
- shortList.add((short)60);
-
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- HessianOutput out = new HessianOutput(bout);
-
- out.writeObject(shortList);
- out.flush();
-
- ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
- HessianInput input = new HessianInput(bin);
-
- List<Class<?>> valueType = new ArrayList<Class<?>>();
- valueType.add(short.class);
-
- List<Short> deserialize = (List) input.readObject(valueType);
- assertTrue(deserialize != null);
- assertTrue(deserialize.size() == 2);
- assertTrue(deserialize.get(1) instanceof Short);
- assertEquals(Short.valueOf((short)0), deserialize.get(0));
- assertEquals(Short.valueOf((short)60), deserialize.get(1));
- }
-
-}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java
index 30991f0..1e6f921 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/Hessian2StringShortTest.java
@@ -82,7 +82,8 @@
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
Hessian2Input input = new Hessian2Input(bin);
- Map deserialize = (Map) input.readObject(HashMap.class, String.class, Short.class);
+// Map deserialize = (Map) input.readObject(HashMap.class, String.class, Short.class);
+ Map deserialize = (Map) input.readObject(HashMap.class);
assertTrue(deserialize != null);
assertTrue(deserialize.size() == 2);
assertTrue(deserialize.get("last") instanceof Short);
@@ -110,7 +111,7 @@
keyValueType.add(String.class);
keyValueType.add(short.class);
- Map deserialize = (Map) input.readObject(keyValueType);
+ Map deserialize = (Map) input.readObject(Map.class);
assertTrue(deserialize != null);
assertTrue(deserialize.size() == 2);
assertTrue(deserialize.get("last") instanceof Short);
@@ -171,7 +172,7 @@
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
Hessian2Input input = new Hessian2Input(bin);
- List<Short> deserialize = (List) input.readObject(ArrayList.class, Short.class);
+ List<Short> deserialize = (List) input.readObject(ArrayList.class);
assertTrue(deserialize != null);
assertTrue(deserialize.size() == 2);
assertTrue(deserialize.get(1) instanceof Short);
@@ -198,7 +199,7 @@
List<Class<?>> valueType = new ArrayList<Class<?>>();
valueType.add(short.class);
- List<Short> deserialize = (List) input.readObject(valueType);
+ List<Short> deserialize = (List) input.readObject(List.class);
assertTrue(deserialize != null);
assertTrue(deserialize.size() == 2);
assertTrue(deserialize.get(1) instanceof Short);
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java
index 000e5dc..95b4447 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/HessianJavaSerializeTest.java
@@ -39,7 +39,7 @@
baseUser.setUserId(1);
baseUser.setUserName("tom");
- BaseUser serializedUser = baseHessianSerialize(baseUser);
+ BaseUser serializedUser = baseHessian2Serialize(baseUser);
Assert.assertEquals("tom", serializedUser.getUserName());
}
@@ -50,7 +50,7 @@
subUser.setUserId(1);
subUser.setUserName("tom");
- SubUser serializedUser = baseHessianSerialize(subUser);
+ SubUser serializedUser = baseHessian2Serialize(subUser);
Assert.assertEquals("tom", serializedUser.getUserName());
}
@@ -78,7 +78,7 @@
grandsonUser.setUserId(1);
grandsonUser.setUserName("tom");
- GrandsonUser serializedUser = baseHessianSerialize(grandsonUser);
+ GrandsonUser serializedUser = baseHessian2Serialize(grandsonUser);
Assert.assertEquals("tom", serializedUser.getUserName());
}
@@ -86,7 +86,6 @@
public void testFloat() throws Exception {
Float fData = 99.8F;
Double dData = 99.8D;
- Assert.assertEquals(dData, baseHessianSerialize(fData));
Assert.assertEquals(dData, baseHessian2Serialize(fData));
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/LocaleSerializerTest.java b/src/test/java/com/alibaba/com/caucho/hessian/io/LocaleSerializerTest.java
index e751438..cd8d85a 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/LocaleSerializerTest.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/LocaleSerializerTest.java
@@ -40,6 +40,5 @@
private void assertLocale(Locale locale) throws IOException {
TestCase.assertEquals(locale, baseHessian2Serialize(locale));
- TestCase.assertEquals(locale, baseHessianSerialize(locale));
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian/io/base/SerializeTestBase.java b/src/test/java/com/alibaba/com/caucho/hessian/io/base/SerializeTestBase.java
index 45478dc..140e6f2 100644
--- a/src/test/java/com/alibaba/com/caucho/hessian/io/base/SerializeTestBase.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian/io/base/SerializeTestBase.java
@@ -18,8 +18,6 @@
import com.alibaba.com.caucho.hessian.io.Hessian2Input;
import com.alibaba.com.caucho.hessian.io.Hessian2Output;
-import com.alibaba.com.caucho.hessian.io.HessianInput;
-import com.alibaba.com.caucho.hessian.io.HessianOutput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -30,25 +28,6 @@
*
*/
public class SerializeTestBase {
- /**
- * hessian serialize util
- *
- * @param data
- * @param <T>
- * @return
- * @throws IOException
- */
- protected <T> T baseHessianSerialize(T data) throws IOException {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- HessianOutput out = new HessianOutput(bout);
-
- out.writeObject(data);
- out.flush();
-
- ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
- HessianInput input = new HessianInput(bin);
- return (T) input.readObject();
- }
/**
* hessian2 serialize util
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/HessianException.java
similarity index 75%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/HessianException.java
index 72a9822..8908c0d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/HessianException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,20 +46,36 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
-
-import java.io.IOException;
+package com.alibaba.com.caucho.hessian3;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Base runtime exception for Hessian exceptions.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class HessianException extends RuntimeException {
/**
- * Looks up a proxy object.
+ * Zero-arg constructor.
*/
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public HessianException() {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianException(String message) {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianException(String message, Throwable rootCause) {
+ super(message, rootCause);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianException(Throwable rootCause) {
+ super(rootCause);
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractDeserializer.java
new file mode 100644
index 0000000..a1ea126
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractDeserializer.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+
+/**
+ * Deserializing an object.
+ */
+abstract public class AbstractDeserializer implements Deserializer {
+ @Override
+ public Class getType() {
+ return Object.class;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in)
+ throws IOException {
+ Object obj = in.readObject();
+
+ String className = getClass().getName();
+
+ if (obj != null)
+ throw error(className + ": unexpected object " + obj.getClass().getName());
+ else
+ throw error(className + ": unexpected null value");
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
+ if (expectType == null) {
+ return readList(in, length);
+ }
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
+ if (expectType == null) {
+ return readLengthList(in, length);
+ }
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ Object obj = in.readObject();
+
+ String className = getClass().getName();
+
+ if (obj != null)
+ throw error(className + ": unexpected object " + obj.getClass().getName());
+ else
+ throw error(className + ": unexpected null value");
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType) throws IOException {
+ if (expectKeyType == null && expectValueType == null) {
+ return readMap(in);
+ }
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ protected HessianProtocolException error(String msg) {
+ return new HessianProtocolException(msg);
+ }
+
+ protected String codeName(int ch) {
+ if (ch < 0)
+ return "end of file";
+ else
+ return "0x" + Integer.toHexString(ch & 0xff);
+ }
+
+ protected SerializerFactory findSerializerFactory(AbstractHessianInput in) {
+ SerializerFactory serializerFactory = null;
+ if (in instanceof Hessian2Input) {
+ serializerFactory = ((Hessian2Input) in).findSerializerFactory();
+ } else if (in instanceof HessianInput) {
+ serializerFactory = ((HessianInput) in).getSerializerFactory();
+ }
+ return serializerFactory == null ? new SerializerFactory() : serializerFactory;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianInput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianInput.java
new file mode 100644
index 0000000..c32a3dd
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianInput.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.List;
+
+/**
+ * Abstract base class for Hessian requests. Hessian users should only
+ * need to use the methods in this class.
+ * <p>
+ * <pre>
+ * AbstractHessianInput in = ...; // get input
+ * String value;
+ *
+ * in.startReply(); // read reply header
+ * value = in.readString(); // read string value
+ * in.completeReply(); // read reply footer
+ * </pre>
+ */
+abstract public class AbstractHessianInput {
+ private HessianRemoteResolver resolver;
+
+ /**
+ * Initialize the Hessian stream with the underlying input stream.
+ */
+ public void init(InputStream is) {
+ }
+
+ /**
+ * Returns the call's method
+ */
+ abstract public String getMethod();
+
+ /**
+ * Sets the resolver used to lookup remote objects.
+ */
+ public HessianRemoteResolver getRemoteResolver() {
+ return resolver;
+ }
+
+ /**
+ * Sets the resolver used to lookup remote objects.
+ */
+ public void setRemoteResolver(HessianRemoteResolver resolver) {
+ this.resolver = resolver;
+ }
+
+ /**
+ * Sets the serializer factory.
+ */
+ public void setSerializerFactory(SerializerFactory ser) {
+ }
+
+ public abstract boolean checkAndReadNull();
+
+ /**
+ * Reads the call
+ * <p>
+ * <pre>
+ * c major minor
+ * </pre>
+ */
+ abstract public int readCall()
+ throws IOException;
+
+ /**
+ * For backward compatibility with HessianSkeleton
+ */
+ public void skipOptionalCall()
+ throws IOException {
+ }
+
+ /**
+ * Reads a header, returning null if there are no headers.
+ * <p>
+ * <pre>
+ * H b16 b8 value
+ * </pre>
+ */
+ abstract public String readHeader()
+ throws IOException;
+
+ /**
+ * Starts reading the call
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * m b16 b8 method
+ * </pre>
+ */
+ abstract public String readMethod()
+ throws IOException;
+
+ /**
+ * Reads the number of method arguments
+ *
+ * @return -1 for a variable length (hessian 1.0)
+ */
+ public int readMethodArgLength()
+ throws IOException {
+ return -1;
+ }
+
+ /**
+ * Starts reading the call, including the headers.
+ * <p>
+ * <p>The call expects the following protocol data
+ * <p>
+ * <pre>
+ * c major minor
+ * m b16 b8 method
+ * </pre>
+ */
+ abstract public void startCall()
+ throws IOException;
+
+ /**
+ * Completes reading the call
+ * <p>
+ * <p>The call expects the following protocol data
+ * <p>
+ * <pre>
+ * Z
+ * </pre>
+ */
+ abstract public void completeCall()
+ throws IOException;
+
+ /**
+ * Reads a reply as an object.
+ * If the reply has a fault, throws the exception.
+ */
+ abstract public Object readReply(Class expectedClass)
+ throws Throwable;
+
+ /**
+ * Starts reading the reply
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * r
+ * v
+ * </pre>
+ */
+ abstract public void startReply()
+ throws Throwable;
+
+ /**
+ * Completes reading the call
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * z
+ * </pre>
+ */
+ abstract public void completeReply()
+ throws IOException;
+
+ /**
+ * Reads a boolean
+ * <p>
+ * <pre>
+ * T
+ * F
+ * </pre>
+ */
+ abstract public boolean readBoolean()
+ throws IOException;
+
+ /**
+ * Reads a null
+ * <p>
+ * <pre>
+ * N
+ * </pre>
+ */
+ abstract public void readNull()
+ throws IOException;
+
+ /**
+ * Reads an integer
+ * <p>
+ * <pre>
+ * I b32 b24 b16 b8
+ * </pre>
+ */
+ abstract public int readInt()
+ throws IOException;
+
+ /**
+ * Reads a long
+ * <p>
+ * <pre>
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ abstract public long readLong()
+ throws IOException;
+
+ /**
+ * Reads a double.
+ * <p>
+ * <pre>
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ abstract public double readDouble()
+ throws IOException;
+
+ /**
+ * Reads a date.
+ * <p>
+ * <pre>
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ abstract public long readUTCDate()
+ throws IOException;
+
+ /**
+ * Reads a string encoded in UTF-8
+ * <p>
+ * <pre>
+ * s b16 b8 non-final string chunk
+ * S b16 b8 final string chunk
+ * </pre>
+ */
+ abstract public String readString()
+ throws IOException;
+
+ /**
+ * Reads an XML node encoded in UTF-8
+ * <p>
+ * <pre>
+ * x b16 b8 non-final xml chunk
+ * X b16 b8 final xml chunk
+ * </pre>
+ */
+ public org.w3c.dom.Node readNode()
+ throws IOException {
+ throw new UnsupportedOperationException(getClass().getSimpleName());
+ }
+
+ /**
+ * Starts reading a string. All the characters must be read before
+ * calling the next method. The actual characters will be read with
+ * the reader's read() or read(char [], int, int).
+ * <p>
+ * <pre>
+ * s b16 b8 non-final string chunk
+ * S b16 b8 final string chunk
+ * </pre>
+ */
+ abstract public Reader getReader()
+ throws IOException;
+
+ /**
+ * Starts reading a byte array using an input stream. All the bytes
+ * must be read before calling the following method.
+ * <p>
+ * <pre>
+ * b b16 b8 non-final binary chunk
+ * B b16 b8 final binary chunk
+ * </pre>
+ */
+ abstract public InputStream readInputStream()
+ throws IOException;
+
+ /**
+ * Reads a byte array.
+ * <p>
+ * <pre>
+ * b b16 b8 non-final binary chunk
+ * B b16 b8 final binary chunk
+ * </pre>
+ */
+ abstract public byte[] readBytes()
+ throws IOException;
+
+ /**
+ * Reads an arbitrary object from the input stream.
+ *
+ * @param expectedClass the expected class if the protocol doesn't supply it.
+ */
+ abstract public Object readObject(Class expectedClass)
+ throws IOException;
+
+ /**
+ * Reads an arbitrary object from the input stream.
+ *
+ * @param expectedClass the expected class if the protocol doesn't supply it.
+ * @param expectedTypes the runtime type hints, eg: expectedClass equals Map, expectedTypes can
+ * equals String.class, Short.class
+ */
+ public Object readObject(Class expectedClass, Class<?>... expectedTypes)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ /**
+ * Reads an arbitrary object from the input stream.
+ */
+ abstract public Object readObject()
+ throws IOException;
+
+ /**
+ * Reads an arbitrary object from the input stream.
+ *
+ * @param expectedTypes the runtime type hints, eg: expectedTypes can
+ * equals String.class, Short.class for HashMap
+ */
+ public Object readObject(List<Class<?>> expectedTypes)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ /**
+ * Reads a remote object reference to the stream. The type is the
+ * type of the remote interface.
+ * <p>
+ * <code><pre>
+ * 'r' 't' b16 b8 type url
+ * </pre></code>
+ */
+ abstract public Object readRemote()
+ throws IOException;
+
+ /**
+ * Reads a reference
+ * <p>
+ * <pre>
+ * R b32 b24 b16 b8
+ * </pre>
+ */
+ abstract public Object readRef()
+ throws IOException;
+
+ /**
+ * Adds an object reference.
+ */
+ abstract public int addRef(Object obj)
+ throws IOException;
+
+ /**
+ * Sets an object reference.
+ */
+ abstract public void setRef(int i, Object obj)
+ throws IOException;
+
+ /**
+ * Resets the references for streaming.
+ */
+ public void resetReferences() {
+ }
+
+ /**
+ * Reads the start of a list
+ */
+ abstract public int readListStart()
+ throws IOException;
+
+ /**
+ * Reads the length of a list.
+ */
+ abstract public int readLength()
+ throws IOException;
+
+ /**
+ * Reads the start of a map
+ */
+ abstract public int readMapStart()
+ throws IOException;
+
+ /**
+ * Reads an object type.
+ */
+ abstract public String readType()
+ throws IOException;
+
+ /**
+ * Returns true if the data has ended.
+ */
+ abstract public boolean isEnd()
+ throws IOException;
+
+ /**
+ * Read the end byte
+ */
+ abstract public void readEnd()
+ throws IOException;
+
+ /**
+ * Read the end byte
+ */
+ abstract public void readMapEnd()
+ throws IOException;
+
+ /**
+ * Read the end byte
+ */
+ abstract public void readListEnd()
+ throws IOException;
+
+ public void close()
+ throws IOException {
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianOutput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianOutput.java
new file mode 100644
index 0000000..3592ec1
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianOutput.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Abstract output stream for Hessian requests.
+ * <p>
+ * <pre>
+ * OutputStream os = ...; // from http connection
+ * AbstractOutput out = new HessianSerializerOutput(os);
+ * String value;
+ *
+ * out.startCall("hello"); // start hello call
+ * out.writeString("arg1"); // write a string argument
+ * out.completeCall(); // complete the call
+ * </pre>
+ */
+abstract public class AbstractHessianOutput {
+ // serializer factory
+ protected SerializerFactory _serializerFactory;
+
+ /**
+ * Gets the serializer factory.
+ */
+ public SerializerFactory getSerializerFactory() {
+ return _serializerFactory;
+ }
+
+ /**
+ * Sets the serializer factory.
+ */
+ public void setSerializerFactory(SerializerFactory factory) {
+ _serializerFactory = factory;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ public final SerializerFactory findSerializerFactory() {
+ SerializerFactory factory = _serializerFactory;
+
+ if (factory == null)
+ _serializerFactory = factory = new SerializerFactory();
+
+ return factory;
+ }
+
+ /**
+ * Initialize the output with a new underlying stream.
+ */
+ public void init(OutputStream os) {
+ }
+
+ /**
+ * Writes a complete method call.
+ */
+ public void call(String method, Object[] args)
+ throws IOException {
+ int length = args != null ? args.length : 0;
+
+ startCall(method, length);
+
+ for (int i = 0; i < length; i++)
+ writeObject(args[i]);
+
+ completeCall();
+ }
+
+ /**
+ * Starts the method call:
+ * <p>
+ * <code><pre>
+ * C
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ abstract public void startCall()
+ throws IOException;
+
+ /**
+ * Starts the method call:
+ * <p>
+ * <code><pre>
+ * C string int
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ abstract public void startCall(String method, int length)
+ throws IOException;
+
+ /**
+ * For Hessian 2.0, use the Header envelope instead
+ *
+ * @deprecated
+ */
+ public void writeHeader(String name)
+ throws IOException {
+ throw new UnsupportedOperationException(getClass().getSimpleName());
+ }
+
+ /**
+ * Writes the method tag.
+ * <p>
+ * <code><pre>
+ * string
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ abstract public void writeMethod(String method)
+ throws IOException;
+
+ /**
+ * Completes the method call:
+ * <p>
+ * <code><pre>
+ * </pre></code>
+ */
+ abstract public void completeCall()
+ throws IOException;
+
+ /**
+ * Writes a boolean value to the stream. The boolean will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * T
+ * F
+ * </pre></code>
+ *
+ * @param value the boolean value to write.
+ */
+ abstract public void writeBoolean(boolean value)
+ throws IOException;
+
+ /**
+ * Writes an integer value to the stream. The integer will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * I b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param value the integer value to write.
+ */
+ abstract public void writeInt(int value)
+ throws IOException;
+
+ /**
+ * Writes a long value to the stream. The long will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param value the long value to write.
+ */
+ abstract public void writeLong(long value)
+ throws IOException;
+
+ /**
+ * Writes a double value to the stream. The double will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param value the double value to write.
+ */
+ abstract public void writeDouble(double value)
+ throws IOException;
+
+ /**
+ * Writes a date to the stream.
+ * <p>
+ * <code><pre>
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param time the date in milliseconds from the epoch in UTC
+ */
+ abstract public void writeUTCDate(long time)
+ throws IOException;
+
+ /**
+ * Writes a null value to the stream.
+ * The null will be written with the following syntax
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeNull()
+ throws IOException;
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * S b16 b8 string-value
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeString(String value)
+ throws IOException;
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * S b16 b8 string-value
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeString(char[] buffer, int offset, int length)
+ throws IOException;
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * B b16 b18 bytes
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeBytes(byte[] buffer)
+ throws IOException;
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * B b16 b18 bytes
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeBytes(byte[] buffer, int offset, int length)
+ throws IOException;
+
+ /**
+ * Writes a byte buffer to the stream.
+ */
+ abstract public void writeByteBufferStart()
+ throws IOException;
+
+ /**
+ * Writes a byte buffer to the stream.
+ * <p>
+ * <code><pre>
+ * b b16 b18 bytes
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeByteBufferPart(byte[] buffer,
+ int offset,
+ int length)
+ throws IOException;
+
+ /**
+ * Writes the last chunk of a byte buffer to the stream.
+ * <p>
+ * <code><pre>
+ * b b16 b18 bytes
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ abstract public void writeByteBufferEnd(byte[] buffer,
+ int offset,
+ int length)
+ throws IOException;
+
+ /**
+ * Writes a reference.
+ * <p>
+ * <code><pre>
+ * Q int
+ * </pre></code>
+ *
+ * @param value the integer value to write.
+ */
+ abstract protected void writeRef(int value)
+ throws IOException;
+
+ /**
+ * Removes a reference.
+ */
+ abstract public boolean removeRef(Object obj)
+ throws IOException;
+
+ /**
+ * Replaces a reference from one object to another.
+ */
+ abstract public boolean replaceRef(Object oldRef, Object newRef)
+ throws IOException;
+
+ /**
+ * Adds an object to the reference list. If the object already exists,
+ * writes the reference, otherwise, the caller is responsible for
+ * the serialization.
+ * <p>
+ * <code><pre>
+ * R b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param object the object to add as a reference.
+ * @return true if the object has already been written.
+ */
+ abstract public boolean addRef(Object object)
+ throws IOException;
+
+ /**
+ * Resets the references for streaming.
+ */
+ public void resetReferences() {
+ }
+
+ /**
+ * Writes a generic object to the output stream.
+ */
+ abstract public void writeObject(Object object)
+ throws IOException;
+
+ /**
+ * Writes the list header to the stream. List writers will call
+ * <code>writeListBegin</code> followed by the list contents and then
+ * call <code>writeListEnd</code>.
+ * <p>
+ * <code><pre>
+ * V
+ * x13 java.util.ArrayList # type
+ * x93 # length=3
+ * x91 # 1
+ * x92 # 2
+ * x93 # 3
+ * </list>
+ * </pre></code>
+ */
+ abstract public boolean writeListBegin(int length, String type)
+ throws IOException;
+
+ /**
+ * Writes the tail of the list to the stream.
+ */
+ abstract public void writeListEnd()
+ throws IOException;
+
+ /**
+ * Writes the map header to the stream. Map writers will call
+ * <code>writeMapBegin</code> followed by the map contents and then
+ * call <code>writeMapEnd</code>.
+ * <p>
+ * <code><pre>
+ * M type (<key> <value>)* Z
+ * </pre></code>
+ */
+ abstract public void writeMapBegin(String type)
+ throws IOException;
+
+ /**
+ * Writes the tail of the map to the stream.
+ */
+ abstract public void writeMapEnd()
+ throws IOException;
+
+ /**
+ * Writes the object header to the stream (for Hessian 2.0), or a
+ * Map for Hessian 1.0. Object writers will call
+ * <code>writeObjectBegin</code> followed by the map contents and then
+ * call <code>writeObjectEnd</code>.
+ * <p>
+ * <code><pre>
+ * C type int <key>*
+ * C int <value>*
+ * </pre></code>
+ *
+ * @return true if the object has already been defined.
+ */
+ public int writeObjectBegin(String type)
+ throws IOException {
+ writeMapBegin(type);
+
+ return -2;
+ }
+
+ /**
+ * Writes the end of the class.
+ */
+ public void writeClassFieldLength(int len)
+ throws IOException {
+ }
+
+ /**
+ * Writes the tail of the object to the stream.
+ */
+ public void writeObjectEnd()
+ throws IOException {
+ }
+
+ public void writeReply(Object o)
+ throws IOException {
+ startReply();
+ writeObject(o);
+ completeReply();
+ }
+
+
+ public void startReply()
+ throws IOException {
+ }
+
+ public void completeReply()
+ throws IOException {
+ }
+
+ public void writeFault(String code, String message, Object detail)
+ throws IOException {
+ }
+
+ public void flush()
+ throws IOException {
+ }
+
+ public void close()
+ throws IOException {
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianResolver.java
similarity index 97%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianResolver.java
index 72a9822..a833ee1 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractHessianResolver.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractListDeserializer.java
similarity index 84%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractListDeserializer.java
index 72a9822..6131978 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractListDeserializer.java
@@ -46,20 +46,22 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing a JDK 1.2 Collection.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class AbstractListDeserializer extends AbstractDeserializer {
@Override
- public Object lookup(String type, String url)
+ public Object readObject(AbstractHessianInput in)
throws IOException {
- return new HessianRemote(type, url);
+ Object obj = in.readObject();
+
+ if (obj != null)
+ throw error("expected list at " + obj.getClass().getName());
+ else
+ throw error("expected list at null");
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractMapDeserializer.java
similarity index 78%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractMapDeserializer.java
index 72a9822..88973ff 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractMapDeserializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,29 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.HashMap;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object for known object types.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class AbstractMapDeserializer extends AbstractDeserializer {
+
@Override
- public Object lookup(String type, String url)
+ public Class getType() {
+ return HashMap.class;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in)
throws IOException {
- return new HessianRemote(type, url);
+ Object obj = in.readObject();
+
+ if (obj != null)
+ throw error("expected map/object at " + obj.getClass().getName());
+ else
+ throw error("expected map/object at null");
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractSerializer.java
similarity index 82%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractSerializer.java
index 72a9822..2afa4a9 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractSerializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,19 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.logging.Logger;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+abstract public class AbstractSerializer implements Serializer {
+ protected static final Logger log
+ = Logger.getLogger(AbstractSerializer.class.getName());
+
@Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
- }
+ abstract public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException;
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractSerializerFactory.java
similarity index 73%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractSerializerFactory.java
index 7c8e328..5754dea 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/AbstractSerializerFactory.java
@@ -46,35 +46,27 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
/**
* Factory for returning serialization methods.
*/
-public class BeanSerializerFactory extends SerializerFactory {
+abstract public class AbstractSerializerFactory {
/**
- * Returns the default serializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
+ * Returns the serializer for a class.
*
* @param cl the class of the object that needs to be serialized.
* @return a serializer object for the serialization.
*/
- @Override
- protected Serializer getDefaultSerializer(Class cl) {
- return new BeanSerializer(cl, getClassLoader());
- }
+ abstract public Serializer getSerializer(Class cl)
+ throws HessianProtocolException;
/**
- * Returns the default deserializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
+ * Returns the deserializer for a class.
*
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
+ * @param cl the class of the object that needs to be deserialized.
+ * @return a deserializer object for the serialization.
*/
- @Override
- protected Deserializer getDefaultDeserializer(Class cl) {
- return new BeanDeserializer(cl);
- }
+ abstract public Deserializer getDeserializer(Class cl)
+ throws HessianProtocolException;
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/ArrayDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ArrayDeserializer.java
new file mode 100644
index 0000000..459a36b
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ArrayDeserializer.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+
+/**
+ * Deserializing a Java array
+ */
+public class ArrayDeserializer extends AbstractListDeserializer {
+ private Class _componentType;
+ private Class _type;
+
+ public ArrayDeserializer(Class componentType) {
+ _componentType = componentType;
+
+ if (_componentType != null) {
+ try {
+ _type = Array.newInstance(_componentType, 0).getClass();
+ } catch (Exception e) {
+ }
+ }
+
+ if (_type == null)
+ _type = Object[].class;
+ }
+
+ @Override
+ public Class getType() {
+ return _type;
+ }
+
+ /**
+ * Reads the array.
+ */
+ @Override
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException {
+ if (length >= 0) {
+ Object[] data = createArray(length);
+
+ in.addRef(data);
+
+ if (_componentType != null) {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject(_componentType);
+ } else {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+ }
+
+ in.readListEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ in.addRef(list);
+
+ if (_componentType != null) {
+ while (!in.isEnd())
+ list.add(in.readObject(_componentType));
+ } else {
+ while (!in.isEnd())
+ list.add(in.readObject());
+ }
+
+ in.readListEnd();
+
+ Object[] data = createArray(list.size());
+ for (int i = 0; i < data.length; i++)
+ data[i] = list.get(i);
+
+ return data;
+ }
+ }
+
+ /**
+ * Reads the array.
+ */
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException {
+ Object[] data = createArray(length);
+
+ in.addRef(data);
+
+ if (_componentType != null) {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject(_componentType);
+ } else {
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+ }
+
+ return data;
+ }
+
+ protected Object[] createArray(int length) {
+ if (_componentType != null)
+ return (Object[]) Array.newInstance(_componentType, length);
+ else
+ return new Object[length];
+ }
+
+ @Override
+ public String toString() {
+ return "ArrayDeserializer[" + _componentType + "]";
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ArraySerializer.java
similarity index 68%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/ArraySerializer.java
index 72a9822..c50a08e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ArraySerializer.java
@@ -46,20 +46,48 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a Java array.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class ArraySerializer extends AbstractSerializer {
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (out.addRef(obj))
+ return;
+
+ Object[] array = (Object[]) obj;
+
+ boolean hasEnd = out.writeListBegin(array.length,
+ getArrayType(obj.getClass()));
+
+ for (int i = 0; i < array.length; i++)
+ out.writeObject(array[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ }
+
+ /**
+ * Returns the <type> name for a <list>.
+ */
+ private String getArrayType(Class cl) {
+ if (cl.isArray())
+ return '[' + getArrayType(cl.getComponentType());
+
+ String name = cl.getName();
+
+ if (name.equals("java.lang.String"))
+ return "string";
+ else if (name.equals("java.lang.Object"))
+ return "object";
+ else if (name.equals("java.util.Date"))
+ return "date";
+ else
+ return name;
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/BasicDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BasicDeserializer.java
new file mode 100644
index 0000000..626e226
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BasicDeserializer.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BasicDeserializer extends AbstractDeserializer {
+ public static final int NULL = BasicSerializer.NULL;
+ public static final int BOOLEAN = BasicSerializer.BOOLEAN;
+ public static final int BYTE = BasicSerializer.BYTE;
+ public static final int SHORT = BasicSerializer.SHORT;
+ public static final int INTEGER = BasicSerializer.INTEGER;
+ public static final int LONG = BasicSerializer.LONG;
+ public static final int FLOAT = BasicSerializer.FLOAT;
+ public static final int DOUBLE = BasicSerializer.DOUBLE;
+ public static final int CHARACTER = BasicSerializer.CHARACTER;
+ public static final int CHARACTER_OBJECT = BasicSerializer.CHARACTER_OBJECT;
+ public static final int STRING = BasicSerializer.STRING;
+ public static final int DATE = BasicSerializer.DATE;
+ public static final int NUMBER = BasicSerializer.NUMBER;
+ public static final int OBJECT = BasicSerializer.OBJECT;
+
+ public static final int BOOLEAN_ARRAY = BasicSerializer.BOOLEAN_ARRAY;
+ public static final int BYTE_ARRAY = BasicSerializer.BYTE_ARRAY;
+ public static final int SHORT_ARRAY = BasicSerializer.SHORT_ARRAY;
+ public static final int INTEGER_ARRAY = BasicSerializer.INTEGER_ARRAY;
+ public static final int LONG_ARRAY = BasicSerializer.LONG_ARRAY;
+ public static final int FLOAT_ARRAY = BasicSerializer.FLOAT_ARRAY;
+ public static final int DOUBLE_ARRAY = BasicSerializer.DOUBLE_ARRAY;
+ public static final int CHARACTER_ARRAY = BasicSerializer.CHARACTER_ARRAY;
+ public static final int STRING_ARRAY = BasicSerializer.STRING_ARRAY;
+ public static final int OBJECT_ARRAY = BasicSerializer.OBJECT_ARRAY;
+
+ private int _code;
+
+ public BasicDeserializer(int code) {
+ _code = code;
+ }
+
+ @Override
+ public Class getType() {
+ switch (_code) {
+ case NULL:
+ return void.class;
+ case BOOLEAN:
+ return Boolean.class;
+ case BYTE:
+ return Byte.class;
+ case SHORT:
+ return Short.class;
+ case INTEGER:
+ return Integer.class;
+ case LONG:
+ return Long.class;
+ case FLOAT:
+ return Float.class;
+ case DOUBLE:
+ return Double.class;
+ case CHARACTER:
+ return Character.class;
+ case CHARACTER_OBJECT:
+ return Character.class;
+ case STRING:
+ return String.class;
+ case DATE:
+ return Date.class;
+ case NUMBER:
+ return Number.class;
+ case OBJECT:
+ return Object.class;
+
+ case BOOLEAN_ARRAY:
+ return boolean[].class;
+ case BYTE_ARRAY:
+ return byte[].class;
+ case SHORT_ARRAY:
+ return short[].class;
+ case INTEGER_ARRAY:
+ return int[].class;
+ case LONG_ARRAY:
+ return long[].class;
+ case FLOAT_ARRAY:
+ return float[].class;
+ case DOUBLE_ARRAY:
+ return double[].class;
+ case CHARACTER_ARRAY:
+ return char[].class;
+ case STRING_ARRAY:
+ return String[].class;
+ case OBJECT_ARRAY:
+ return Object[].class;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in)
+ throws IOException {
+ if (in.checkAndReadNull()) {
+ return null;
+ }
+ switch (_code) {
+ case NULL:
+ // hessian/3490
+ in.readObject();
+
+ return null;
+
+ case BOOLEAN:
+ return Boolean.valueOf(in.readBoolean());
+
+ case BYTE:
+ return Byte.valueOf((byte) in.readInt());
+
+ case SHORT:
+ return Short.valueOf((short) in.readInt());
+
+ case INTEGER:
+ return Integer.valueOf(in.readInt());
+
+ case LONG:
+ return Long.valueOf(in.readLong());
+
+ case FLOAT:
+ return Float.valueOf((float) in.readDouble());
+
+ case DOUBLE:
+ return Double.valueOf(in.readDouble());
+
+ case STRING:
+ return in.readString();
+
+ case OBJECT:
+ return in.readObject();
+
+ case CHARACTER: {
+ String s = in.readString();
+ if (s == null || s.equals(""))
+ return Character.valueOf((char) 0);
+ else
+ return Character.valueOf(s.charAt(0));
+ }
+
+ case CHARACTER_OBJECT: {
+ String s = in.readString();
+ if (s == null || s.equals(""))
+ return null;
+ else
+ return Character.valueOf(s.charAt(0));
+ }
+
+ case DATE:
+ return new Date(in.readUTCDate());
+
+ case NUMBER:
+ return in.readObject();
+
+ case BYTE_ARRAY:
+ return in.readBytes();
+
+ case CHARACTER_ARRAY: {
+ String s = in.readString();
+
+ if (s == null)
+ return null;
+ else {
+ int len = s.length();
+ char[] chars = new char[len];
+ s.getChars(0, len, chars, 0);
+ return chars;
+ }
+ }
+
+ case BOOLEAN_ARRAY:
+ case SHORT_ARRAY:
+ case INTEGER_ARRAY:
+ case LONG_ARRAY:
+ case FLOAT_ARRAY:
+ case DOUBLE_ARRAY:
+ case STRING_ARRAY: {
+ int code = in.readListStart();
+
+ switch (code) {
+ case 'N':
+ return null;
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ int length = code - 0x10;
+ in.readInt();
+
+ return readLengthList(in, length);
+
+ default:
+ String type = in.readType();
+ length = in.readLength();
+
+ return readList(in, length);
+ }
+ }
+
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException {
+ switch (_code) {
+ case BOOLEAN_ARRAY: {
+ if (length >= 0) {
+ boolean[] data = new boolean[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readBoolean();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(Boolean.valueOf(in.readBoolean()));
+
+ in.readEnd();
+
+ boolean[] data = new boolean[list.size()];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Boolean) list.get(i)).booleanValue();
+
+ return data;
+ }
+ }
+
+ case SHORT_ARRAY: {
+ if (length >= 0) {
+ short[] data = new short[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (short) in.readInt();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(Short.valueOf((short) in.readInt()));
+
+ in.readEnd();
+
+ short[] data = new short[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Short) list.get(i)).shortValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case INTEGER_ARRAY: {
+ if (length >= 0) {
+ int[] data = new int[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readInt();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(Integer.valueOf(in.readInt()));
+
+
+ in.readEnd();
+
+ int[] data = new int[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Integer) list.get(i)).intValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case LONG_ARRAY: {
+ if (length >= 0) {
+ long[] data = new long[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readLong();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(Long.valueOf(in.readLong()));
+
+ in.readEnd();
+
+ long[] data = new long[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Long) list.get(i)).longValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case FLOAT_ARRAY: {
+ if (length >= 0) {
+ float[] data = new float[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (float) in.readDouble();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(new Float(in.readDouble()));
+
+ in.readEnd();
+
+ float[] data = new float[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Float) list.get(i)).floatValue();
+
+ in.addRef(data);
+
+ return data;
+ }
+ }
+
+ case DOUBLE_ARRAY: {
+ if (length >= 0) {
+ double[] data = new double[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readDouble();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(new Double(in.readDouble()));
+
+ in.readEnd();
+
+ double[] data = new double[list.size()];
+ in.addRef(data);
+ for (int i = 0; i < data.length; i++)
+ data[i] = ((Double) list.get(i)).doubleValue();
+
+ return data;
+ }
+ }
+
+ case STRING_ARRAY: {
+ if (length >= 0) {
+ String[] data = new String[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readString();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ while (!in.isEnd())
+ list.add(in.readString());
+
+ in.readEnd();
+
+ String[] data = new String[list.size()];
+ in.addRef(data);
+ for (int i = 0; i < data.length; i++)
+ data[i] = (String) list.get(i);
+
+ return data;
+ }
+ }
+
+ case OBJECT_ARRAY: {
+ if (length >= 0) {
+ Object[] data = new Object[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+
+ in.readEnd();
+
+ return data;
+ } else {
+ ArrayList list = new ArrayList();
+
+ in.addRef(list); // XXX: potential issues here
+
+ while (!in.isEnd())
+ list.add(in.readObject());
+
+ in.readEnd();
+
+ Object[] data = new Object[list.size()];
+ for (int i = 0; i < data.length; i++)
+ data[i] = (Object) list.get(i);
+
+ return data;
+ }
+ }
+
+ default:
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException {
+ switch (_code) {
+ case BOOLEAN_ARRAY: {
+ boolean[] data = new boolean[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readBoolean();
+
+ return data;
+ }
+
+ case SHORT_ARRAY: {
+ short[] data = new short[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (short) in.readInt();
+
+ return data;
+ }
+
+ case INTEGER_ARRAY: {
+ int[] data = new int[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readInt();
+
+ return data;
+ }
+
+ case LONG_ARRAY: {
+ long[] data = new long[length];
+
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readLong();
+
+ return data;
+ }
+
+ case FLOAT_ARRAY: {
+ float[] data = new float[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = (float) in.readDouble();
+
+ return data;
+ }
+
+ case DOUBLE_ARRAY: {
+ double[] data = new double[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readDouble();
+
+ return data;
+ }
+
+ case STRING_ARRAY: {
+ String[] data = new String[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readString();
+
+ return data;
+ }
+
+ case OBJECT_ARRAY: {
+ Object[] data = new Object[length];
+ in.addRef(data);
+
+ for (int i = 0; i < data.length; i++)
+ data[i] = in.readObject();
+
+ return data;
+ }
+
+ default:
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+ }
+
+ public String toString()
+ {
+ return getClass().getSimpleName() + "[" + _code + "]";
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/BasicSerializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BasicSerializer.java
new file mode 100644
index 0000000..d9a68ff
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BasicSerializer.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BasicSerializer extends AbstractSerializer {
+ public static final int NULL = 0;
+ public static final int BOOLEAN = NULL + 1;
+ public static final int BYTE = BOOLEAN + 1;
+ public static final int SHORT = BYTE + 1;
+ public static final int INTEGER = SHORT + 1;
+ public static final int LONG = INTEGER + 1;
+ public static final int FLOAT = LONG + 1;
+ public static final int DOUBLE = FLOAT + 1;
+ public static final int CHARACTER = DOUBLE + 1;
+ public static final int CHARACTER_OBJECT = CHARACTER + 1;
+ public static final int STRING = CHARACTER_OBJECT + 1;
+ public static final int DATE = STRING + 1;
+ public static final int NUMBER = DATE + 1;
+ public static final int OBJECT = NUMBER + 1;
+
+ public static final int BOOLEAN_ARRAY = OBJECT + 1;
+ public static final int BYTE_ARRAY = BOOLEAN_ARRAY + 1;
+ public static final int SHORT_ARRAY = BYTE_ARRAY + 1;
+ public static final int INTEGER_ARRAY = SHORT_ARRAY + 1;
+ public static final int LONG_ARRAY = INTEGER_ARRAY + 1;
+ public static final int FLOAT_ARRAY = LONG_ARRAY + 1;
+ public static final int DOUBLE_ARRAY = FLOAT_ARRAY + 1;
+ public static final int CHARACTER_ARRAY = DOUBLE_ARRAY + 1;
+ public static final int STRING_ARRAY = CHARACTER_ARRAY + 1;
+ public static final int OBJECT_ARRAY = STRING_ARRAY + 1;
+
+ private int code;
+
+ public BasicSerializer(int code) {
+ this.code = code;
+ }
+
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ switch (code) {
+ case BOOLEAN:
+ out.writeBoolean(((Boolean) obj).booleanValue());
+ break;
+
+ case BYTE:
+ case SHORT:
+ case INTEGER:
+ out.writeInt(((Number) obj).intValue());
+ break;
+
+ case LONG:
+ out.writeLong(((Number) obj).longValue());
+ break;
+
+ case FLOAT:
+ out.writeDouble(Double.parseDouble(String.valueOf(((Number) obj).floatValue())));
+ break;
+ case DOUBLE:
+ out.writeDouble(((Number) obj).doubleValue());
+ break;
+
+ case CHARACTER:
+ case CHARACTER_OBJECT:
+ out.writeString(String.valueOf(obj));
+ break;
+
+ case STRING:
+ out.writeString((String) obj);
+ break;
+
+ case DATE:
+ out.writeUTCDate(((Date) obj).getTime());
+ break;
+
+ case BOOLEAN_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ boolean[] data = (boolean[]) obj;
+ boolean hasEnd = out.writeListBegin(data.length, "[boolean");
+ for (int i = 0; i < data.length; i++)
+ out.writeBoolean(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+
+ break;
+ }
+
+ case BYTE_ARRAY: {
+ byte[] data = (byte[]) obj;
+ out.writeBytes(data, 0, data.length);
+ break;
+ }
+
+ case SHORT_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ short[] data = (short[]) obj;
+ boolean hasEnd = out.writeListBegin(data.length, "[short");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeInt(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case INTEGER_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ int[] data = (int[]) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[int");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeInt(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+
+ break;
+ }
+
+ case LONG_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ long[] data = (long[]) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[long");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeLong(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case FLOAT_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ float[] data = (float[]) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[float");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeDouble(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case DOUBLE_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ double[] data = (double[]) obj;
+ boolean hasEnd = out.writeListBegin(data.length, "[double");
+
+ for (int i = 0; i < data.length; i++)
+ out.writeDouble(data[i]);
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case STRING_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ String[] data = (String[]) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[string");
+
+ for (int i = 0; i < data.length; i++) {
+ out.writeString(data[i]);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case CHARACTER_ARRAY: {
+ char[] data = (char[]) obj;
+ out.writeString(data, 0, data.length);
+ break;
+ }
+
+ case OBJECT_ARRAY: {
+ if (out.addRef(obj))
+ return;
+
+ Object[] data = (Object[]) obj;
+
+ boolean hasEnd = out.writeListBegin(data.length, "[object");
+
+ for (int i = 0; i < data.length; i++) {
+ out.writeObject(data[i]);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
+ break;
+ }
+
+ case NULL:
+ out.writeNull();
+ break;
+
+ default:
+ throw new RuntimeException(code + " " + String.valueOf(obj.getClass()));
+ }
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanDeserializer.java
new file mode 100644
index 0000000..db412cd
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanDeserializer.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class BeanDeserializer extends AbstractMapDeserializer {
+ private Class _type;
+ private HashMap _methodMap;
+ private Method _readResolve;
+ private Constructor _constructor;
+ private Object[] _constructorArgs;
+
+ public BeanDeserializer(Class cl) {
+ _type = cl;
+ _methodMap = getMethodMap(cl);
+
+ _readResolve = getReadResolve(cl);
+
+ Constructor[] constructors = cl.getConstructors();
+ int bestLength = Integer.MAX_VALUE;
+
+ for (int i = 0; i < constructors.length; i++) {
+ if (constructors[i].getParameterTypes().length < bestLength) {
+ _constructor = constructors[i];
+ bestLength = _constructor.getParameterTypes().length;
+ }
+ }
+
+ if (_constructor != null) {
+ _constructor.setAccessible(true);
+ Class[] params = _constructor.getParameterTypes();
+ _constructorArgs = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ _constructorArgs[i] = getParamArg(params[i]);
+ }
+ }
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected static Object getParamArg(Class cl) {
+ if (!cl.isPrimitive())
+ return null;
+ else if (boolean.class.equals(cl))
+ return Boolean.FALSE;
+ else if (byte.class.equals(cl))
+ return Byte.valueOf((byte) 0);
+ else if (short.class.equals(cl))
+ return Short.valueOf((short) 0);
+ else if (char.class.equals(cl))
+ return Character.valueOf((char) 0);
+ else if (int.class.equals(cl))
+ return Integer.valueOf(0);
+ else if (long.class.equals(cl))
+ return Long.valueOf(0);
+ else if (float.class.equals(cl))
+ return Double.valueOf(0);
+ else if (double.class.equals(cl))
+ return Double.valueOf(0);
+ else
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Class getType() {
+ return _type;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readMap(in, obj);
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ public Object readMap(AbstractHessianInput in, Object obj)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ while (!in.isEnd()) {
+ Object key = in.readObject();
+
+ Method method = (Method) _methodMap.get(key);
+
+ if (method != null) {
+ Object value = in.readObject(method.getParameterTypes()[0]);
+
+ method.invoke(obj, new Object[]{value});
+ } else {
+ Object value = in.readObject();
+ }
+ }
+
+ in.readMapEnd();
+
+ Object resolve = resolve(obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ private Object resolve(Object obj) {
+ // if there's a readResolve method, call it
+ try {
+ if (_readResolve != null)
+ return _readResolve.invoke(obj, new Object[0]);
+ } catch (Exception e) {
+ }
+
+ return obj;
+ }
+
+ protected Object instantiate()
+ throws Exception {
+ return _constructor.newInstance(_constructorArgs);
+ }
+
+ /**
+ * Returns the readResolve method
+ */
+ protected Method getReadResolve(Class cl) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("readResolve") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected HashMap getMethodMap(Class cl) {
+ HashMap methodMap = new HashMap();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (Modifier.isStatic(method.getModifiers()))
+ continue;
+
+ String name = method.getName();
+
+ if (!name.startsWith("set"))
+ continue;
+
+ Class[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length != 1)
+ continue;
+
+ if (!method.getReturnType().equals(void.class))
+ continue;
+
+ if (findGetter(methods, name, paramTypes[0]) == null)
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ method.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ name = name.substring(3);
+
+ int j = 0;
+ for (; j < name.length() && Character.isUpperCase(name.charAt(j)); j++) {
+ }
+
+ if (j == 1)
+ name = name.substring(0, j).toLowerCase() + name.substring(j);
+ else if (j > 1)
+ name = name.substring(0, j - 1).toLowerCase() + name.substring(j - 1);
+
+
+ methodMap.put(name, method);
+ }
+ }
+
+ return methodMap;
+ }
+
+ /**
+ * Finds any matching setter.
+ */
+ private Method findGetter(Method[] methods, String setterName, Class arg) {
+ String getterName = "get" + setterName.substring(3);
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (!method.getName().equals(getterName))
+ continue;
+
+ if (!method.getReturnType().equals(arg))
+ continue;
+
+ Class[] params = method.getParameterTypes();
+
+ if (params.length == 0)
+ return method;
+ }
+
+ return null;
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanSerializer.java
similarity index 99%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializer.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/BeanSerializer.java
index a3a8ba5..6da2f1e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializer.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanSerializer.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.lang.reflect.Method;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanSerializerFactory.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/BeanSerializerFactory.java
index 7c8e328..b0f9d2f 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BeanSerializerFactory.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
/**
* Factory for returning serialization methods.
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BigIntegerDeserializer.java
similarity index 95%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/BigIntegerDeserializer.java
index 5cd0498..4592621 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BigIntegerDeserializer.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BigIntegerDeserializer.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.math.BigInteger;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BitSetHandle.java
similarity index 81%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/BitSetHandle.java
index 72a9822..92665c6 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BitSetHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,20 +46,25 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
-import java.io.IOException;
+import java.util.BitSet;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Handle for a BitSet object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+public class BitSetHandle implements java.io.Serializable, HessianHandle {
+ private long[] words;
+
+ public BitSetHandle(long[] words) {
+ this.words = words;
+ }
+
+ private Object readResolve() {
+ if (words == null) {
+ return null;
+ }
+
+ return BitSet.valueOf(words);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/BitSetSerializer.java
similarity index 79%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/BitSetSerializer.java
index 72a9822..5754128 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/BitSetSerializer.java
@@ -46,20 +46,30 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.BitSet;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a BitSet.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class BitSetSerializer extends AbstractSerializer {
+ private static BitSetSerializer SERIALIZER = new BitSetSerializer();
+
+ public static BitSetSerializer create() {
+ return SERIALIZER;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ BitSet bitSet = (BitSet) obj;
+
+ out.writeObject(new BitSetHandle(bitSet.toLongArray()));
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/CalendarHandle.java
similarity index 69%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/CalendarHandle.java
index 72a9822..42f4347 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/CalendarHandle.java
@@ -46,20 +46,45 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
-import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Handle for a calendar object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+public class CalendarHandle implements java.io.Serializable, HessianHandle {
+ private Class type;
+ private Date date;
+
+ public CalendarHandle() {
+ }
+
+ public CalendarHandle(Class type, long time) {
+ if (!GregorianCalendar.class.equals(type))
+ this.type = type;
+
+ this.date = new Date(time);
+ }
+
+ private Object readResolve() {
+ try {
+ Calendar cal;
+
+ if (this.type != null)
+ cal = (Calendar) this.type.newInstance();
+ else
+ cal = new GregorianCalendar();
+
+ cal.setTimeInMillis(this.date.getTime());
+
+ return cal;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/CalendarSerializer.java
similarity index 78%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/CalendarSerializer.java
index 72a9822..b8e4187 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/CalendarSerializer.java
@@ -46,20 +46,31 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.Calendar;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a calendar.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class CalendarSerializer extends AbstractSerializer {
+ private static CalendarSerializer SERIALIZER = new CalendarSerializer();
+
+ public static CalendarSerializer create() {
+ return SERIALIZER;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ Calendar cal = (Calendar) obj;
+
+ out.writeObject(new CalendarHandle(cal.getClass(),
+ cal.getTimeInMillis()));
+ }
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassDeserializer.java
new file mode 100644
index 0000000..9c5d151
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassDeserializer.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Deserializing a JDK 1.2 Class.
+ */
+public class ClassDeserializer extends AbstractMapDeserializer {
+ private static final HashMap<String, Class> _primClasses
+ = new HashMap<String, Class>();
+
+ static {
+ _primClasses.put("void", void.class);
+ _primClasses.put("boolean", boolean.class);
+ _primClasses.put("java.lang.Boolean", Boolean.class);
+ _primClasses.put("byte", byte.class);
+ _primClasses.put("java.lang.Byte", Byte.class);
+ _primClasses.put("char", char.class);
+ _primClasses.put("java.lang.Character", Character.class);
+ _primClasses.put("short", short.class);
+ _primClasses.put("java.lang.Short", Short.class);
+ _primClasses.put("int", int.class);
+ _primClasses.put("java.lang.Integer", Integer.class);
+ _primClasses.put("long", long.class);
+ _primClasses.put("java.lang.Long", Long.class);
+ _primClasses.put("float", float.class);
+ _primClasses.put("java.lang.Float", Float.class);
+ _primClasses.put("double", double.class);
+ _primClasses.put("java.lang.Double", Double.class);
+ _primClasses.put("java.lang.String", String.class);
+ }
+
+ private ClassLoader _loader;
+
+ public ClassDeserializer(ClassLoader loader) {
+ _loader = loader;
+ }
+
+ @Override
+ public Class getType() {
+ return Class.class;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ int ref = in.addRef(null);
+
+ String name = null;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("name"))
+ name = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object value = create(name);
+
+ in.setRef(ref, value);
+
+ return value;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ int ref = in.addRef(null);
+
+ String name = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("name".equals(fieldNames[i]))
+ name = in.readString();
+ else
+ in.readObject();
+ }
+
+ Object value = create(name);
+
+ in.setRef(ref, value);
+
+ return value;
+ }
+
+ Object create(String name)
+ throws IOException {
+ if (name == null)
+ throw new IOException("Serialized Class expects name.");
+
+ Class cl = _primClasses.get(name);
+
+ if (cl != null)
+ return cl;
+
+ try {
+ if (_loader != null)
+ return Class.forName(name, false, _loader);
+ else
+ return Class.forName(name);
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassFactory.java
new file mode 100644
index 0000000..e63863c
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassFactory.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+/**
+ * Loads a class from the classloader.
+ */
+public class ClassFactory
+{
+ protected static final Logger log
+ = Logger.getLogger(ClassFactory.class.getName());
+ private static final ArrayList<Allow> _staticAllowList;
+ private static final Map<String, Object> _allowSubClassSet = new ConcurrentHashMap<>();
+ private static final Map<String, Object> _allowClassSet = new ConcurrentHashMap<>();
+
+ private ClassLoader _loader;
+ private boolean _isWhitelist;
+
+ private LinkedList<Allow> _allowList;
+
+ ClassFactory(ClassLoader loader)
+ {
+ _loader = loader;
+ initAllow();
+ }
+
+ public Class<?> load(String className)
+ throws ClassNotFoundException
+ {
+ if (isAllow(className)) {
+ Class<?> aClass = Class.forName(className, false, _loader);
+
+ if (_allowClassSet.containsKey(className)) {
+ return aClass;
+ }
+
+ if (aClass.getInterfaces().length > 0) {
+ for (Class<?> anInterface : aClass.getInterfaces()) {
+ if(!isAllow(anInterface.getName())) {
+ log.log(Level.SEVERE, className + "'s interfaces: " + anInterface.getName() + " in blacklist or not in whitelist, deserialization with type 'HashMap' instead.");
+ return HashMap.class;
+ }
+ }
+ }
+
+ List<Class<?>> allSuperClasses = new LinkedList<>();
+
+ Class<?> superClass = aClass.getSuperclass();
+ while (superClass != null) {
+ // add current super class
+ allSuperClasses.add(superClass);
+ superClass = superClass.getSuperclass();
+ }
+
+ for (Class<?> aSuperClass : allSuperClasses) {
+ if(!isAllow(aSuperClass.getName())) {
+ log.log(Level.SEVERE, className + "'s superClass: " + aSuperClass.getName() + " in blacklist or not in whitelist, deserialization with type 'HashMap' instead.");
+ return HashMap.class;
+ }
+
+ }
+
+ _allowClassSet.put(className, className);
+ return aClass;
+ }
+ else {
+ log.log(Level.SEVERE, className + " in blacklist or not in whitelist, deserialization with type 'HashMap' instead.");
+ return HashMap.class;
+ }
+ }
+
+ private boolean isAllow(String className)
+ {
+ LinkedList<Allow> allowList = _allowList;
+
+ if (allowList == null) {
+ return true;
+ }
+
+ if (_allowSubClassSet.containsKey(className)) {
+ return true;
+ }
+
+ for (Allow allow : allowList) {
+ Boolean isAllow = allow.allow(className);
+
+ if (isAllow != null) {
+ if (isAllow) {
+ _allowSubClassSet.put(className, className);
+ }
+ return isAllow;
+ }
+ }
+
+ if (_isWhitelist) {
+ return false;
+ }
+
+ _allowSubClassSet.put(className, className);
+ return true;
+ }
+
+ public void setWhitelist(boolean isWhitelist)
+ {
+ _allowClassSet.clear();
+ _allowSubClassSet.clear();
+ _isWhitelist = isWhitelist;
+
+ initAllow();
+ }
+
+ public void allow(String pattern)
+ {
+ _allowClassSet.clear();
+ _allowSubClassSet.clear();
+ initAllow();
+
+ synchronized (this) {
+ _allowList.addFirst(new Allow(toPattern(pattern), true));
+ }
+ }
+
+ public void deny(String pattern)
+ {
+ _allowClassSet.clear();
+ _allowSubClassSet.clear();
+ initAllow();
+
+ synchronized (this) {
+ _allowList.addFirst(new Allow(toPattern(pattern), false));
+ }
+ }
+
+ private static String toPattern(String pattern)
+ {
+ pattern = pattern.replace(".", "\\.");
+ pattern = pattern.replace("*", ".*");
+
+ return pattern;
+ }
+
+ private void initAllow()
+ {
+ synchronized (this) {
+ if (_allowList == null) {
+ _allowList = new LinkedList<Allow>();
+ _allowList.addAll(_staticAllowList);
+ }
+ }
+ }
+
+ static class Allow {
+ private Boolean _isAllow;
+ private Pattern _pattern;
+
+ public Allow() {
+ }
+
+ private Allow(String pattern, boolean isAllow)
+ {
+ _isAllow = isAllow;
+ _pattern = Pattern.compile(pattern);
+ }
+
+ Boolean allow(String className)
+ {
+ if (_pattern.matcher(className).matches()) {
+ return _isAllow;
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ static class AllowPrefix extends Allow {
+ private Boolean _isAllow;
+ private String _prefix;
+
+ private AllowPrefix(String prefix, boolean isAllow)
+ {
+ super();
+ _isAllow = isAllow;
+ _prefix = prefix;
+ }
+
+ @Override
+ Boolean allow(String className)
+ {
+ if (className.startsWith(_prefix)) {
+ return _isAllow;
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ static {
+ _staticAllowList = new ArrayList<Allow>();
+
+ ClassLoader classLoader = ClassFactory.class.getClassLoader();
+ try {
+ String[] denyClasses = readLines(classLoader.getResourceAsStream("DENY_CLASS"));
+ for (String denyClass : denyClasses) {
+ if (denyClass.startsWith("#")) {
+ continue;
+ }
+ if (denyClass.endsWith(".")) {
+ _staticAllowList.add(new AllowPrefix(denyClass, false));
+ } else {
+ _staticAllowList.add(new Allow(toPattern(denyClass), false));
+ }
+ }
+ } catch (IOException ignore) {
+
+ }
+ }
+
+ /**
+ * read lines.
+ *
+ * @param is input stream.
+ * @return lines.
+ * @throws IOException If an I/O error occurs
+ */
+ public static String[] readLines(InputStream is) throws IOException {
+ List<String> lines = new ArrayList<String>();
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ lines.add(line);
+ }
+ return lines.toArray(new String[0]);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassSerializer.java
similarity index 72%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/ClassSerializer.java
index 72a9822..0c0d10f 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ClassSerializer.java
@@ -46,20 +46,39 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a remote object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class ClassSerializer extends AbstractSerializer {
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ Class cl = (Class) obj;
+
+ if (cl == null) {
+ out.writeNull();
+ } else if (out.addRef(obj)) {
+ return;
+ } else {
+ int ref = out.writeObjectBegin("java.lang.Class");
+
+ if (ref < -1) {
+ out.writeString("name");
+ out.writeString(cl.getName());
+ out.writeMapEnd();
+ } else {
+ if (ref == -1) {
+ out.writeInt(1);
+ out.writeString("name");
+ out.writeObjectBegin("java.lang.Class");
+ }
+
+ out.writeString(cl.getName());
+ }
+ }
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/CollectionDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/CollectionDeserializer.java
new file mode 100644
index 0000000..b652528
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/CollectionDeserializer.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Deserializing a JDK 1.2 Collection.
+ */
+public class CollectionDeserializer extends AbstractListDeserializer {
+ private Class _type;
+
+ public CollectionDeserializer(Class type) {
+ _type = type;
+ }
+
+ @Override
+ public Class getType() {
+ return _type;
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException {
+ return readList(in, length, _type);
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
+ Collection list = createList();
+
+ in.addRef(list);
+
+ Deserializer deserializer = null;
+
+ SerializerFactory factory = findSerializerFactory(in);
+ if (expectType != null) {
+ deserializer = factory.getDeserializer(expectType.getName());
+ }
+
+ while (!in.isEnd()) {
+ list.add(deserializer != null ? deserializer.readObject(in) : in.readObject());
+ }
+
+
+ in.readEnd();
+
+ return list;
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException {
+ return readList(in, length, null);
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType) throws IOException {
+ Collection list = createList();
+
+ in.addRef(list);
+
+ Deserializer deserializer = null;
+
+ SerializerFactory factory = findSerializerFactory(in);
+ if (expectType != null) {
+ deserializer = factory.getDeserializer(expectType.getName());
+ }
+
+ for (; length > 0; length--) {
+ list.add(deserializer != null ? deserializer.readObject(in) : in.readObject());
+ }
+
+
+ return list;
+ }
+
+ private Collection createList()
+ throws IOException {
+ Collection list = null;
+
+ if (_type == null)
+ list = new ArrayList();
+ else if (!_type.isInterface()) {
+ try {
+ list = (Collection) _type.newInstance();
+ } catch (Exception e) {
+ }
+ }
+
+ if (list != null) {
+ } else if (SortedSet.class.isAssignableFrom(_type))
+ list = new TreeSet();
+ else if (Set.class.isAssignableFrom(_type))
+ list = new HashSet();
+ else if (List.class.isAssignableFrom(_type))
+ list = new ArrayList();
+ else if (Collection.class.isAssignableFrom(_type))
+ list = new ArrayList();
+ else {
+ try {
+ list = (Collection) _type.newInstance();
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ return list;
+ }
+
+ public String toString()
+ {
+ return getClass().getSimpleName() + "[" + _type + "]";
+ }
+}
+
+
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/CollectionSerializer.java
similarity index 67%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/CollectionSerializer.java
index 72a9822..5740fd0 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/CollectionSerializer.java
@@ -46,20 +46,53 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a JDK 1.2 Collection.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class CollectionSerializer extends AbstractSerializer {
+ private boolean _sendJavaType = true;
+
/**
- * Looks up a proxy object.
+ * Return true if the java type of the collection should be sent.
*/
+ public boolean getSendJavaType() {
+ return _sendJavaType;
+ }
+
+ /**
+ * Set true if the java type of the collection should be sent.
+ */
+ public void setSendJavaType(boolean sendJavaType) {
+ _sendJavaType = sendJavaType;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (out.addRef(obj))
+ return;
+
+ Collection list = (Collection) obj;
+
+ Class cl = obj.getClass();
+ boolean hasEnd = out.writeListBegin(list.size(), obj.getClass().getName());
+
+ Iterator iter = list.iterator();
+ while (iter.hasNext()) {
+ Object value = iter.next();
+
+ out.writeObject(value);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/Deflation.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Deflation.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/Deflation.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/Deflation.java
index 11380ad..8638d82 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/Deflation.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Deflation.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianEnvelope.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Deserializer.java
similarity index 61%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/HessianEnvelope.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/Deserializer.java
index 21bd3a7..84d60c8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianEnvelope.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Deserializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,33 +46,64 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Factory class for wrapping and unwrapping hessian streams.
+ * Deserializing an object.
+ *
*/
-abstract public class HessianEnvelope {
- /**
- * Wrap the Hessian output stream in an envelope.
- */
- abstract public Hessian2Output wrap(Hessian2Output out)
+public interface Deserializer {
+ public Class getType();
+
+ public Object readObject(AbstractHessianInput in)
+ throws IOException;
+
+ public Object readList(AbstractHessianInput in, int length)
throws IOException;
/**
- * Unwrap the Hessian input stream with this envelope. It is an
- * error if the actual envelope does not match the expected envelope
- * class.
+ * deserialize list object from expect type.
+ *
+ * @param in
+ * @param length
+ * @param expectType
+ * @return
+ * @throws IOException
*/
- abstract public Hessian2Input unwrap(Hessian2Input in)
+ public Object readList(AbstractHessianInput in, int length, Class<?> expectType)
+ throws IOException;
+
+ public Object readLengthList(AbstractHessianInput in, int length)
throws IOException;
/**
- * Unwrap the envelope after having read the envelope code ('E') and
- * the envelope method. Called by the EnvelopeFactory for dynamic
- * reading of the envelopes.
+ * deserialize list object from expect type.
+ *
+ * @param in
+ * @param length
+ * @param expectType
+ * @return
+ * @throws IOException
*/
- abstract public Hessian2Input unwrapHeaders(Hessian2Input in)
+ public Object readLengthList(AbstractHessianInput in, int length, Class<?> expectType)
+ throws IOException;
+
+ public Object readMap(AbstractHessianInput in)
+ throws IOException;
+
+ /**
+ * deserialize map object from expect key and value type.
+ * @param in
+ * @param expectKeyType
+ * @param expectValueType
+ * @return
+ * @throws IOException
+ */
+ public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType)
+ throws IOException;
+
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
throws IOException;
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumDeserializer.java
new file mode 100644
index 0000000..331d324
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumDeserializer.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+/**
+ * Deserializing an enum valued object
+ */
+public class EnumDeserializer extends AbstractDeserializer {
+ private Class _enumType;
+ private Method _valueOf;
+
+ public EnumDeserializer(Class cl) {
+ // hessian/33b[34], hessian/3bb[78]
+ if (cl.isEnum())
+ _enumType = cl;
+ else if (cl.getSuperclass().isEnum())
+ _enumType = cl.getSuperclass();
+ else
+ throw new RuntimeException("Class " + cl.getName() + " is not an enum");
+
+ try {
+ _valueOf = _enumType.getMethod("valueOf",
+ new Class[]{Class.class, String.class});
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Class getType() {
+ return _enumType;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ String name = null;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("name"))
+ name = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object obj = create(name);
+
+ in.addRef(obj);
+
+ return obj;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ String name = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("name".equals(fieldNames[i]))
+ name = in.readString();
+ else
+ in.readObject();
+ }
+
+ Object obj = create(name);
+
+ in.addRef(obj);
+
+ return obj;
+ }
+
+ private Object create(String name)
+ throws IOException {
+ if (name == null)
+ throw new IOException(_enumType.getName() + " expects name.");
+
+ try {
+ return _valueOf.invoke(null, _enumType, name);
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSerializer.java
similarity index 60%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSerializer.java
index 7c8e328..23bf4a3 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSerializer.java
@@ -46,35 +46,61 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
/**
- * Factory for returning serialization methods.
+ * Serializing an object for known object types.
*/
-public class BeanSerializerFactory extends SerializerFactory {
- /**
- * Returns the default serializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
- */
- @Override
- protected Serializer getDefaultSerializer(Class cl) {
- return new BeanSerializer(cl, getClassLoader());
+public class EnumSerializer extends AbstractSerializer {
+ private Method _name;
+
+ public EnumSerializer(Class cl) {
+ // hessian/32b[12], hessian/3ab[23]
+ if (!cl.isEnum() && cl.getSuperclass().isEnum())
+ cl = cl.getSuperclass();
+
+ try {
+ _name = cl.getMethod("name", new Class[0]);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
- /**
- * Returns the default deserializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
- */
@Override
- protected Deserializer getDefaultDeserializer(Class cl) {
- return new BeanDeserializer(cl);
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ if (out.addRef(obj))
+ return;
+
+ Class cl = obj.getClass();
+
+ if (!cl.isEnum() && cl.getSuperclass().isEnum())
+ cl = cl.getSuperclass();
+
+ String name = null;
+ try {
+ name = (String) _name.invoke(obj, (Object[]) null);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ out.writeString("name");
+ out.writeString(name);
+ out.writeMapEnd();
+ } else {
+ if (ref == -1) {
+ out.writeClassFieldLength(1);
+ out.writeString("name");
+ out.writeObjectBegin(cl.getName());
+ }
+
+ out.writeString(name);
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetHandler.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSetHandler.java
similarity index 96%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetHandler.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSetHandler.java
index 3c0a623..4150ad1 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetHandler.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSetHandler.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.Serializable;
import java.util.Arrays;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetSerializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSetSerializer.java
similarity index 97%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetSerializer.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSetSerializer.java
index 9fa4535..b277c16 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnumSetSerializer.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumSetSerializer.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.lang.reflect.Field;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumerationDeserializer.java
similarity index 76%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/EnumerationDeserializer.java
index 72a9822..7841a72 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumerationDeserializer.java
@@ -46,20 +46,38 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.Vector;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing a JDK 1.2 Collection.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class EnumerationDeserializer extends AbstractListDeserializer {
+ private static EnumerationDeserializer _deserializer;
+
+ public static EnumerationDeserializer create() {
+ if (_deserializer == null)
+ _deserializer = new EnumerationDeserializer();
+
+ return _deserializer;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public Object readList(AbstractHessianInput in, int length)
throws IOException {
- return new HessianRemote(type, url);
+ Vector list = new Vector();
+
+ in.addRef(list);
+
+ while (!in.isEnd())
+ list.add(in.readObject());
+
+ in.readEnd();
+
+ return list.elements();
}
}
+
+
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumerationSerializer.java
similarity index 74%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/EnumerationSerializer.java
index 72a9822..040b126 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnumerationSerializer.java
@@ -46,20 +46,38 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.Enumeration;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a JDK 1.2 Enumeration.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class EnumerationSerializer extends AbstractSerializer {
+ private static EnumerationSerializer _serializer;
+
+ public static EnumerationSerializer create() {
+ if (_serializer == null)
+ _serializer = new EnumerationSerializer();
+
+ return _serializer;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ Enumeration iter = (Enumeration) obj;
+
+ boolean hasEnd = out.writeListBegin(-1, null);
+
+ while (iter.hasMoreElements()) {
+ Object value = iter.nextElement();
+
+ out.writeObject(value);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnvelopeFactory.java
similarity index 97%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/EnvelopeFactory.java
index be505fb..764a7b3 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/EnvelopeFactory.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.util.logging.Logger;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/ExtSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ExtSerializerFactory.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/ExtSerializerFactory.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/ExtSerializerFactory.java
index 1b11a44..8b1168a 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/ExtSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ExtSerializerFactory.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.util.HashMap;
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Constants.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Constants.java
new file mode 100644
index 0000000..cdf39c3
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Constants.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+public interface Hessian2Constants {
+ public static final int BC_BINARY = 'B'; // final chunk
+ public static final int BC_BINARY_CHUNK = 'A'; // non-final chunk
+ public static final int BC_BINARY_DIRECT = 0x20; // 1-byte length binary
+ public static final int BINARY_DIRECT_MAX = 0x0f;
+ public static final int BC_BINARY_SHORT = 0x34; // 2-byte length binary
+ public static final int BINARY_SHORT_MAX = 0x3ff; // 0-1023 binary
+
+ public static final int BC_CLASS_DEF = 'C'; // object/class definition
+
+ public static final int BC_DATE = 0x4a; // 64-bit millisecond UTC date
+ public static final int BC_DATE_MINUTE = 0x4b; // 32-bit minute UTC date
+
+ public static final int BC_DOUBLE = 'D'; // IEEE 64-bit double
+
+ public static final int BC_DOUBLE_ZERO = 0x5b;
+ public static final int BC_DOUBLE_ONE = 0x5c;
+ public static final int BC_DOUBLE_BYTE = 0x5d;
+ public static final int BC_DOUBLE_SHORT = 0x5e;
+ public static final int BC_DOUBLE_MILL = 0x5f;
+
+ public static final int BC_FALSE = 'F'; // boolean false
+
+ public static final int BC_INT = 'I'; // 32-bit int
+
+ public static final int INT_DIRECT_MIN = -0x10;
+ public static final int INT_DIRECT_MAX = 0x2f;
+ public static final int BC_INT_ZERO = 0x90;
+
+ public static final int INT_BYTE_MIN = -0x800;
+ public static final int INT_BYTE_MAX = 0x7ff;
+ public static final int BC_INT_BYTE_ZERO = 0xc8;
+
+ public static final int BC_END = 'Z';
+
+ public static final int INT_SHORT_MIN = -0x40000;
+ public static final int INT_SHORT_MAX = 0x3ffff;
+ public static final int BC_INT_SHORT_ZERO = 0xd4;
+
+ public static final int BC_LIST_VARIABLE = 0x55;
+ public static final int BC_LIST_FIXED = 'V';
+ public static final int BC_LIST_VARIABLE_UNTYPED = 0x57;
+ public static final int BC_LIST_FIXED_UNTYPED = 0x58;
+
+ public static final int BC_LIST_DIRECT = 0x70;
+ public static final int BC_LIST_DIRECT_UNTYPED = 0x78;
+ public static final int LIST_DIRECT_MAX = 0x7;
+
+ public static final int BC_LONG = 'L'; // 64-bit signed integer
+ public static final long LONG_DIRECT_MIN = -0x08;
+ public static final long LONG_DIRECT_MAX = 0x0f;
+ public static final int BC_LONG_ZERO = 0xe0;
+
+ public static final long LONG_BYTE_MIN = -0x800;
+ public static final long LONG_BYTE_MAX = 0x7ff;
+ public static final int BC_LONG_BYTE_ZERO = 0xf8;
+
+ public static final int LONG_SHORT_MIN = -0x40000;
+ public static final int LONG_SHORT_MAX = 0x3ffff;
+ public static final int BC_LONG_SHORT_ZERO = 0x3c;
+
+ public static final int BC_LONG_INT = 0x59;
+
+ public static final int BC_MAP = 'M';
+ public static final int BC_MAP_UNTYPED = 'H';
+
+ public static final int BC_NULL = 'N';
+
+ public static final int BC_OBJECT = 'O';
+ public static final int BC_OBJECT_DEF = 'C';
+
+ public static final int BC_OBJECT_DIRECT = 0x60;
+ public static final int OBJECT_DIRECT_MAX = 0x0f;
+
+ public static final int BC_REF = 0x51;
+
+ public static final int BC_STRING = 'S'; // final string
+ public static final int BC_STRING_CHUNK = 'R'; // non-final string
+
+ public static final int BC_STRING_DIRECT = 0x00;
+ public static final int STRING_DIRECT_MAX = 0x1f;
+ public static final int BC_STRING_SHORT = 0x30;
+ public static final int STRING_SHORT_MAX = 0x3ff;
+
+ public static final int BC_TRUE = 'T';
+
+ public static final int P_PACKET_CHUNK = 0x4f;
+ public static final int P_PACKET = 'P';
+
+ public static final int P_PACKET_DIRECT = 0x80;
+ public static final int PACKET_DIRECT_MAX = 0x7f;
+
+ public static final int P_PACKET_SHORT = 0x70;
+ public static final int PACKET_SHORT_MAX = 0xfff;
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Input.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Input.java
new file mode 100644
index 0000000..995ad9d
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Input.java
@@ -0,0 +1,3659 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Input stream for Hessian requests.
+ * <p>
+ * <p>HessianInput is unbuffered, so any client needs to provide
+ * its own buffering.
+ * <p>
+ * <pre>
+ * InputStream is = ...; // from http connection
+ * HessianInput in = new HessianInput(is);
+ * String value;
+ *
+ * in.startReply(); // read reply header
+ * value = in.readString(); // read string value
+ * in.completeReply(); // read reply footer
+ * </pre>
+ */
+public class Hessian2Input
+ extends AbstractHessianInput
+ implements Hessian2Constants {
+ private static final Logger log
+ = Logger.getLogger(Hessian2Input.class.getName());
+
+ private static final double D_256 = 1.0 / 256.0;
+ private static final int END_OF_DATA = -2;
+ private static final int SIZE = 256;
+ private static final int GAP = 16;
+ private static Field _detailMessageField;
+ private static boolean _isCloseStreamOnClose;
+
+ static {
+ try {
+ _detailMessageField = Throwable.class.getDeclaredField("detailMessage");
+ _detailMessageField.setAccessible(true);
+ } catch (Throwable e) {
+ }
+ }
+
+ private final byte[] _buffer = new byte[SIZE];
+ // factory for deserializing objects in the input stream
+ protected SerializerFactory _serializerFactory;
+ protected ArrayList _refs;
+ protected ArrayList _classDefs;
+ protected ArrayList _types;
+ // the underlying input stream
+ private InputStream _is;
+ // a peek character
+ private int _offset;
+ private int _length;
+ // true for streaming data
+ private boolean _isStreaming;
+ // the method for a call
+ private String _method;
+ private Throwable _replyFault;
+ private StringBuilder _sbuf = new StringBuilder();
+ // true if this is the last chunk
+ private boolean _isLastChunk;
+ // the chunk length
+ private int _chunkLength;
+
+ /**
+ * Creates a new Hessian input stream, initialized with an
+ * underlying input stream.
+ *
+ * @param is the underlying input stream.
+ */
+ public Hessian2Input(InputStream is) {
+ _is = is;
+ }
+
+ /**
+ * Gets the serializer factory.
+ */
+ public SerializerFactory getSerializerFactory() {
+ return _serializerFactory;
+ }
+
+ /**
+ * Sets the serializer factory.
+ */
+ @Override
+ public void setSerializerFactory(SerializerFactory factory) {
+ _serializerFactory = factory;
+ }
+
+ /**
+ * Gets the serializer factory, creating a default if necessary.
+ */
+ public final SerializerFactory findSerializerFactory() {
+ SerializerFactory factory = _serializerFactory;
+
+ if (factory == null)
+ _serializerFactory = factory = new SerializerFactory();
+
+ return factory;
+ }
+
+ public boolean isCloseStreamOnClose() {
+ return _isCloseStreamOnClose;
+ }
+
+ public void setCloseStreamOnClose(boolean isClose) {
+ _isCloseStreamOnClose = isClose;
+ }
+
+ /**
+ * Returns the calls method
+ */
+ @Override
+ public String getMethod() {
+ return _method;
+ }
+
+ /**
+ * Returns any reply fault.
+ */
+ public Throwable getReplyFault() {
+ return _replyFault;
+ }
+
+ @Override
+ public void init(InputStream is) {
+ _is = is;
+
+ reset();
+ }
+
+ public void reset() {
+ resetReferences();
+
+ if (_classDefs != null) {
+ _classDefs.clear();
+ }
+
+ if (_types != null) {
+ _types.clear();
+ }
+
+ _offset = 0;
+ _length = 0;
+ }
+
+ @Override
+ public boolean checkAndReadNull() {
+ try {
+ int tag = read();
+ if ('N' == tag) {
+ return true;
+ }
+ if (-1 != tag) {
+ _offset--;
+ }
+ } catch (IOException ignored) {
+ }
+ return false;
+ }
+
+ /**
+ * Starts reading the call
+ * <p>
+ * <pre>
+ * c major minor
+ * </pre>
+ */
+ @Override
+ public int readCall()
+ throws IOException {
+ int tag = read();
+
+ if (tag != 'C')
+ throw error("expected hessian call ('C') at " + codeName(tag));
+
+ return 0;
+ }
+
+ /**
+ * Starts reading the envelope
+ * <p>
+ * <pre>
+ * E major minor
+ * </pre>
+ */
+ public int readEnvelope()
+ throws IOException {
+ int tag = read();
+ int version = 0;
+
+ if (tag == 'H') {
+ int major = read();
+ int minor = read();
+
+ version = (major << 16) + minor;
+
+ tag = read();
+ }
+
+ if (tag != 'E')
+ throw error("expected hessian Envelope ('E') at " + codeName(tag));
+
+ return version;
+ }
+
+ /**
+ * Completes reading the envelope
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * Z
+ * </pre>
+ */
+ public void completeEnvelope()
+ throws IOException {
+ int tag = read();
+
+ if (tag != 'Z')
+ error("expected end of envelope at " + codeName(tag));
+ }
+
+ /**
+ * Starts reading the call
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * string
+ * </pre>
+ */
+ @Override
+ public String readMethod()
+ throws IOException {
+ _method = readString();
+
+ return _method;
+ }
+
+ /**
+ * Returns the number of method arguments
+ * <p>
+ * <pre>
+ * int
+ * </pre>
+ */
+ @Override
+ public int readMethodArgLength()
+ throws IOException {
+ return readInt();
+ }
+
+ /**
+ * Starts reading the call, including the headers.
+ * <p>
+ * <p>The call expects the following protocol data
+ * <p>
+ * <pre>
+ * c major minor
+ * m b16 b8 method
+ * </pre>
+ */
+ @Override
+ public void startCall()
+ throws IOException {
+ readCall();
+
+ readMethod();
+ }
+
+ /**
+ * Completes reading the call
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * </pre>
+ */
+ @Override
+ public void completeCall()
+ throws IOException {
+ }
+
+ /**
+ * Reads a reply as an object.
+ * If the reply has a fault, throws the exception.
+ */
+ @Override
+ public Object readReply(Class expectedClass)
+ throws Throwable {
+ int tag = read();
+
+ if (tag == 'R')
+ return readObject(expectedClass);
+ else if (tag == 'F') {
+ HashMap map = (HashMap) readObject(HashMap.class);
+
+ throw prepareFault(map);
+ } else {
+ StringBuilder sb = new StringBuilder();
+ sb.append((char) tag);
+
+ try {
+ int ch;
+
+ while ((ch = read()) >= 0) {
+ sb.append((char) ch);
+ }
+ } catch (IOException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ throw error("expected hessian reply at " + codeName(tag) + "\n"
+ + sb);
+ }
+ }
+
+ /**
+ * Starts reading the reply
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * r
+ * </pre>
+ */
+ @Override
+ public void startReply()
+ throws Throwable {
+ // XXX: for variable length (?)
+
+ readReply(Object.class);
+ }
+
+ /**
+ * Prepares the fault.
+ */
+ private Throwable prepareFault(HashMap fault)
+ throws IOException {
+ Object detail = fault.get("detail");
+ String message = (String) fault.get("message");
+
+ if (detail instanceof Throwable) {
+ _replyFault = (Throwable) detail;
+
+ if (message != null && _detailMessageField != null) {
+ try {
+ _detailMessageField.set(_replyFault, message);
+ } catch (Throwable e) {
+ }
+ }
+
+ return _replyFault;
+ } else {
+ String code = (String) fault.get("code");
+
+ _replyFault = new HessianServiceException(message, code, detail);
+
+ return _replyFault;
+ }
+ }
+
+ /**
+ * Completes reading the call
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * z
+ * </pre>
+ */
+ @Override
+ public void completeReply()
+ throws IOException {
+ }
+
+ /**
+ * Completes reading the call
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * z
+ * </pre>
+ */
+ public void completeValueReply()
+ throws IOException {
+ int tag = read();
+
+ if (tag != 'Z')
+ error("expected end of reply at " + codeName(tag));
+ }
+
+ /**
+ * Reads a header, returning null if there are no headers.
+ * <p>
+ * <pre>
+ * H b16 b8 value
+ * </pre>
+ */
+ @Override
+ public String readHeader()
+ throws IOException {
+ return null;
+ }
+
+ /**
+ * Starts reading the message
+ * <p>
+ * <pre>
+ * p major minor
+ * </pre>
+ */
+ public int startMessage()
+ throws IOException {
+ int tag = read();
+
+ if (tag != 'p' && tag != 'P') {
+ throw error("expected Hessian message ('p') at " + codeName(tag));
+ }
+
+ int major = read();
+ int minor = read();
+
+ return (major << 16) + minor;
+ }
+
+ /**
+ * Completes reading the message
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * z
+ * </pre>
+ */
+ public void completeMessage()
+ throws IOException {
+ int tag = read();
+
+ if (tag != 'Z')
+ error("expected end of message at " + codeName(tag));
+ }
+
+ /**
+ * Reads a null
+ * <p>
+ * <pre>
+ * N
+ * </pre>
+ */
+ @Override
+ public void readNull()
+ throws IOException {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return;
+
+ default:
+ throw expect("null", tag);
+ }
+ }
+
+ /**
+ * Reads a boolean
+ * <p>
+ * <pre>
+ * T
+ * F
+ * </pre>
+ */
+ @Override
+ public boolean readBoolean()
+ throws IOException {
+ int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ switch (tag) {
+ case 'T':
+ return true;
+ case 'F':
+ return false;
+
+ // direct integer
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return tag != BC_INT_ZERO;
+
+ // INT_BYTE = 0
+ case 0xc8:
+ return read() != 0;
+
+ // INT_BYTE != 0
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ read();
+ return true;
+
+ // INT_SHORT = 0
+ case 0xd4:
+ return (256 * read() + read()) != 0;
+
+ // INT_SHORT != 0
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ read();
+ read();
+ return true;
+
+ case 'I':
+ return
+ parseInt() != 0;
+
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ return tag != BC_LONG_ZERO;
+
+ // LONG_BYTE = 0
+ case 0xf8:
+ return read() != 0;
+
+ // LONG_BYTE != 0
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ read();
+ return true;
+
+ // INT_SHORT = 0
+ case 0x3c:
+ return (256 * read() + read()) != 0;
+
+ // INT_SHORT != 0
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ read();
+ read();
+ return true;
+
+ case BC_LONG_INT:
+ return (0x1000000L * read()
+ + 0x10000L * read()
+ + 0x100 * read()
+ + read()) != 0;
+
+ case 'L':
+ return parseLong() != 0;
+
+ case BC_DOUBLE_ZERO:
+ return false;
+
+ case BC_DOUBLE_ONE:
+ return true;
+
+ case BC_DOUBLE_BYTE:
+ return read() != 0;
+
+ case BC_DOUBLE_SHORT:
+ return (0x100 * read() + read()) != 0;
+
+ case BC_DOUBLE_MILL: {
+ int mills = parseInt();
+
+ return mills != 0;
+ }
+
+ case 'D':
+ return parseDouble() != 0.0;
+
+ case 'N':
+ return false;
+
+ default:
+ throw expect("boolean", tag);
+ }
+ }
+
+ /**
+ * Reads a short
+ * <p>
+ * <pre>
+ * I b32 b24 b16 b8
+ * </pre>
+ */
+ public short readShort()
+ throws IOException {
+ return (short) readInt();
+ }
+
+ /**
+ * Reads an integer
+ * <p>
+ * <pre>
+ * I b32 b24 b16 b8
+ * </pre>
+ */
+ @Override
+ public final int readInt()
+ throws IOException {
+ //int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return 0;
+
+ case 'F':
+ return 0;
+
+ case 'T':
+ return 1;
+
+ // direct integer
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return tag - BC_INT_ZERO;
+
+ /* byte int */
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
+
+ /* short int */
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
+
+ case 'I':
+ case BC_LONG_INT:
+ return ((read() << 24)
+ + (read() << 16)
+ + (read() << 8)
+ + read());
+
+ // direct long
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ return tag - BC_LONG_ZERO;
+
+ /* byte long */
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ return ((tag - BC_LONG_BYTE_ZERO) << 8) + read();
+
+ /* short long */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
+
+ case 'L':
+ return (int) parseLong();
+
+ case BC_DOUBLE_ZERO:
+ return 0;
+
+ case BC_DOUBLE_ONE:
+ return 1;
+
+ //case LONG_BYTE:
+ case BC_DOUBLE_BYTE:
+ return (byte) (_offset < _length ? _buffer[_offset++] : read());
+
+ //case INT_SHORT:
+ //case LONG_SHORT:
+ case BC_DOUBLE_SHORT:
+ return (short) (256 * read() + read());
+
+ case BC_DOUBLE_MILL: {
+ int mills = parseInt();
+
+ return (int) (0.001 * mills);
+ }
+
+ case 'D':
+ return (int) parseDouble();
+
+ default:
+ throw expect("integer", tag);
+ }
+ }
+
+ /**
+ * Reads a long
+ * <p>
+ * <pre>
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ @Override
+ public long readLong()
+ throws IOException {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return 0;
+
+ case 'F':
+ return 0;
+
+ case 'T':
+ return 1;
+
+ // direct integer
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return tag - BC_INT_ZERO;
+
+ /* byte int */
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
+
+ /* short int */
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
+
+ //case LONG_BYTE:
+ case BC_DOUBLE_BYTE:
+ return (byte) (_offset < _length ? _buffer[_offset++] : read());
+
+ //case INT_SHORT:
+ //case LONG_SHORT:
+ case BC_DOUBLE_SHORT:
+ return (short) (256 * read() + read());
+
+ case 'I':
+ case BC_LONG_INT:
+ return parseInt();
+
+ // direct long
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ return tag - BC_LONG_ZERO;
+
+ /* byte long */
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ return ((tag - BC_LONG_BYTE_ZERO) << 8) + read();
+
+ /* short long */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
+
+ case 'L':
+ return parseLong();
+
+ case BC_DOUBLE_ZERO:
+ return 0;
+
+ case BC_DOUBLE_ONE:
+ return 1;
+
+ case BC_DOUBLE_MILL: {
+ int mills = parseInt();
+
+ return (long) (0.001 * mills);
+ }
+
+ case 'D':
+ return (long) parseDouble();
+
+ default:
+ throw expect("long", tag);
+ }
+ }
+
+ /**
+ * Reads a float
+ * <p>
+ * <pre>
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ public float readFloat()
+ throws IOException {
+ return (float) readDouble();
+ }
+
+ /**
+ * Reads a double
+ * <p>
+ * <pre>
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ @Override
+ public double readDouble()
+ throws IOException {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return 0;
+
+ case 'F':
+ return 0;
+
+ case 'T':
+ return 1;
+
+ // direct integer
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return tag - 0x90;
+
+ /* byte int */
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ return ((tag - BC_INT_BYTE_ZERO) << 8) + read();
+
+ /* short int */
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ return ((tag - BC_INT_SHORT_ZERO) << 16) + 256 * read() + read();
+
+ case 'I':
+ case BC_LONG_INT:
+ return parseInt();
+
+ // direct long
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ return tag - BC_LONG_ZERO;
+
+ /* byte long */
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ return ((tag - BC_LONG_BYTE_ZERO) << 8) + read();
+
+ /* short long */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ return ((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read();
+
+ case 'L':
+ return (double) parseLong();
+
+ case BC_DOUBLE_ZERO:
+ return 0;
+
+ case BC_DOUBLE_ONE:
+ return 1;
+
+ case BC_DOUBLE_BYTE:
+ return (byte) (_offset < _length ? _buffer[_offset++] : read());
+
+ case BC_DOUBLE_SHORT:
+ return (short) (256 * read() + read());
+
+ case BC_DOUBLE_MILL: {
+ int mills = parseInt();
+
+ return 0.001 * mills;
+ }
+
+ case 'D':
+ return parseDouble();
+
+ default:
+ throw expect("double", tag);
+ }
+ }
+
+ /**
+ * Reads a date.
+ * <p>
+ * <pre>
+ * T b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ @Override
+ public long readUTCDate()
+ throws IOException {
+ int tag = read();
+
+ if (tag == BC_DATE) {
+ return parseLong();
+ } else if (tag == BC_DATE_MINUTE) {
+ return parseInt() * 60000L;
+ } else
+ throw expect("date", tag);
+ }
+
+ /**
+ * Reads a byte from the stream.
+ */
+ public int readChar()
+ throws IOException {
+ if (_chunkLength > 0) {
+ _chunkLength--;
+ if (_chunkLength == 0 && _isLastChunk)
+ _chunkLength = END_OF_DATA;
+
+ int ch = parseUTF8Char();
+ return ch;
+ } else if (_chunkLength == END_OF_DATA) {
+ _chunkLength = 0;
+ return -1;
+ }
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return -1;
+
+ case 'S':
+ case BC_STRING_CHUNK:
+ _isLastChunk = tag == 'S';
+ _chunkLength = (read() << 8) + read();
+
+ _chunkLength--;
+ int value = parseUTF8Char();
+
+ // special code so successive read byte won't
+ // be read as a single object.
+ if (_chunkLength == 0 && _isLastChunk)
+ _chunkLength = END_OF_DATA;
+
+ return value;
+
+ default:
+ throw expect("char", tag);
+ }
+ }
+
+ /**
+ * Reads a byte array from the stream.
+ */
+ public int readString(char[] buffer, int offset, int length)
+ throws IOException {
+ int readLength = 0;
+
+ if (_chunkLength == END_OF_DATA) {
+ _chunkLength = 0;
+ return -1;
+ } else if (_chunkLength == 0) {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return -1;
+
+ case 'S':
+ case BC_STRING_CHUNK:
+ _isLastChunk = tag == 'S';
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ _isLastChunk = true;
+ _chunkLength = tag - 0x00;
+ break;
+
+ default:
+ throw expect("string", tag);
+ }
+ }
+
+ while (length > 0) {
+ if (_chunkLength > 0) {
+ buffer[offset++] = (char) parseUTF8Char();
+ _chunkLength--;
+ length--;
+ readLength++;
+ } else if (_isLastChunk) {
+ if (readLength == 0)
+ return -1;
+ else {
+ _chunkLength = END_OF_DATA;
+ return readLength;
+ }
+ } else {
+ int tag = read();
+
+ switch (tag) {
+ case 'S':
+ case BC_STRING_CHUNK:
+ _isLastChunk = tag == 'S';
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ default:
+ throw expect("string", tag);
+ }
+ }
+ }
+
+ if (readLength == 0)
+ return -1;
+ else if (_chunkLength > 0 || !_isLastChunk)
+ return readLength;
+ else {
+ _chunkLength = END_OF_DATA;
+ return readLength;
+ }
+ }
+
+ /**
+ * Reads a string
+ * <p>
+ * <pre>
+ * S b16 b8 string value
+ * </pre>
+ */
+ @Override
+ public String readString()
+ throws IOException {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return null;
+ case 'T':
+ return "true";
+ case 'F':
+ return "false";
+
+ // direct integer
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return String.valueOf((tag - 0x90));
+
+ /* byte int */
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ return String.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read());
+
+ /* short int */
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ return String.valueOf(((tag - BC_INT_SHORT_ZERO) << 16)
+ + 256 * read() + read());
+
+ case 'I':
+ case BC_LONG_INT:
+ return String.valueOf(parseInt());
+
+ // direct long
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ return String.valueOf(tag - BC_LONG_ZERO);
+
+ /* byte long */
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ return String.valueOf(((tag - BC_LONG_BYTE_ZERO) << 8) + read());
+
+ /* short long */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ return String.valueOf(((tag - BC_LONG_SHORT_ZERO) << 16)
+ + 256 * read() + read());
+
+ case 'L':
+ return String.valueOf(parseLong());
+
+ case BC_DOUBLE_ZERO:
+ return "0.0";
+
+ case BC_DOUBLE_ONE:
+ return "1.0";
+
+ case BC_DOUBLE_BYTE:
+ return String.valueOf((byte) (_offset < _length
+ ? _buffer[_offset++]
+ : read()));
+
+ case BC_DOUBLE_SHORT:
+ return String.valueOf(((short) (256 * read() + read())));
+
+ case BC_DOUBLE_MILL: {
+ int mills = parseInt();
+
+ return String.valueOf(0.001 * mills);
+ }
+
+ case 'D':
+ return String.valueOf(parseDouble());
+
+ case 'S':
+ case BC_STRING_CHUNK:
+ _isLastChunk = tag == 'S';
+ _chunkLength = (read() << 8) + read();
+
+ _sbuf.setLength(0);
+ int ch;
+
+ while ((ch = parseChar()) >= 0)
+ _sbuf.append((char) ch);
+
+ return _sbuf.toString();
+
+ // 0-byte string
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ _isLastChunk = true;
+ _chunkLength = tag - 0x00;
+
+ _sbuf.setLength(0);
+
+ while ((ch = parseChar()) >= 0)
+ _sbuf.append((char) ch);
+
+ return _sbuf.toString();
+
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x30) * 256 + read();
+
+ _sbuf.setLength(0);
+
+ while ((ch = parseChar()) >= 0)
+ _sbuf.append((char) ch);
+
+ return _sbuf.toString();
+
+ default:
+ throw expect("string", tag);
+ }
+ }
+
+ /**
+ * Reads a byte array
+ * <p>
+ * <pre>
+ * B b16 b8 data value
+ * </pre>
+ */
+ @Override
+ public byte[] readBytes()
+ throws IOException {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return null;
+
+ case 'B':
+ case BC_BINARY_CHUNK:
+ _isLastChunk = tag == 'B';
+ _chunkLength = (read() << 8) + read();
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ int data;
+ while ((data = parseByte()) >= 0)
+ bos.write(data);
+
+ return bos.toByteArray();
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f: {
+ _isLastChunk = true;
+ _chunkLength = tag - 0x20;
+
+ byte[] buffer = new byte[_chunkLength];
+
+ int k = 0;
+ while ((data = parseByte()) >= 0)
+ buffer[k++] = (byte) data;
+
+ return buffer;
+ }
+
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+
+ byte[] buffer = new byte[_chunkLength];
+ int k = 0;
+
+ while ((data = parseByte()) >= 0) {
+ buffer[k++] = (byte) data;
+ }
+
+ return buffer;
+ }
+
+ default:
+ throw expect("bytes", tag);
+ }
+ }
+
+ /**
+ * Reads a byte from the stream.
+ */
+ public int readByte()
+ throws IOException {
+ if (_chunkLength > 0) {
+ _chunkLength--;
+ if (_chunkLength == 0 && _isLastChunk)
+ _chunkLength = END_OF_DATA;
+
+ return read();
+ } else if (_chunkLength == END_OF_DATA) {
+ _chunkLength = 0;
+ return -1;
+ }
+
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return -1;
+
+ case 'B':
+ case BC_BINARY_CHUNK:
+ _isLastChunk = tag == 'B';
+ _chunkLength = (read() << 8) + read();
+
+ int value = parseByte();
+
+ // special code so successive read byte won't
+ // be read as a single object.
+ if (_chunkLength == 0 && _isLastChunk)
+ _chunkLength = END_OF_DATA;
+
+ return value;
+
+ default:
+ throw expect("binary", tag);
+ }
+ }
+
+ /**
+ * Reads a byte array from the stream.
+ */
+ public int readBytes(byte[] buffer, int offset, int length)
+ throws IOException {
+ int readLength = 0;
+
+ if (_chunkLength == END_OF_DATA) {
+ _chunkLength = 0;
+ return -1;
+ } else if (_chunkLength == 0) {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return -1;
+
+ case 'B':
+ case BC_BINARY_CHUNK:
+ _isLastChunk = tag == 'B';
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ default:
+ throw expect("binary", tag);
+ }
+ }
+
+ while (length > 0) {
+ if (_chunkLength > 0) {
+ buffer[offset++] = (byte) read();
+ _chunkLength--;
+ length--;
+ readLength++;
+ } else if (_isLastChunk) {
+ if (readLength == 0)
+ return -1;
+ else {
+ _chunkLength = END_OF_DATA;
+ return readLength;
+ }
+ } else {
+ int tag = read();
+
+ switch (tag) {
+ case 'B':
+ case BC_BINARY_CHUNK:
+ _isLastChunk = tag == 'B';
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ default:
+ throw expect("binary", tag);
+ }
+ }
+ }
+
+ if (readLength == 0)
+ return -1;
+ else if (_chunkLength > 0 || !_isLastChunk)
+ return readLength;
+ else {
+ _chunkLength = END_OF_DATA;
+ return readLength;
+ }
+ }
+
+ /**
+ * Reads a fault.
+ */
+ private HashMap readFault()
+ throws IOException {
+ HashMap map = new HashMap();
+
+ int code = read();
+ for (; code > 0 && code != 'Z'; code = read()) {
+ _offset--;
+
+ Object key = readObject();
+ Object value = readObject();
+
+ if (key != null && value != null)
+ map.put(key, value);
+ }
+
+ if (code != 'Z')
+ throw expect("fault", code);
+
+ return map;
+ }
+
+ /**
+ * Reads an object from the input stream with an expected type.
+ */
+ @Override
+ public Object readObject(Class cl)
+ throws IOException {
+ return readObject(cl, null, null);
+ }
+
+ @Override
+ public Object readObject(Class expectedClass, Class<?>... expectedTypes) throws IOException {
+ if (expectedClass == null || expectedClass == Object.class)
+ return readObject();
+
+ int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ switch (tag) {
+ case 'N':
+ return null;
+
+ case 'H': {
+ Deserializer reader = findSerializerFactory().getDeserializer(expectedClass);
+
+ boolean keyValuePair = expectedTypes != null && expectedTypes.length == 2;
+ // fix deserialize of short type
+ return reader.readMap(this
+ , keyValuePair ? expectedTypes[0] : null
+ , keyValuePair ? expectedTypes[1] : null);
+ }
+
+ case 'M': {
+ String type = readType();
+
+ // hessian/3bb3
+ if ("".equals(type)) {
+ Deserializer reader;
+ reader = findSerializerFactory().getDeserializer(expectedClass);
+
+ return reader.readMap(this);
+ } else {
+ Deserializer reader;
+ reader = findSerializerFactory().getObjectDeserializer(type, expectedClass);
+
+ return reader.readMap(this);
+ }
+ }
+
+ case 'C': {
+ readObjectDefinition(expectedClass);
+
+ return readObject(expectedClass);
+ }
+
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f: {
+ int ref = tag - 0x60;
+ int size = _classDefs.size();
+
+ if (ref < 0 || size <= ref)
+ throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
+
+ ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+
+ return readObjectInstance(expectedClass, def);
+ }
+
+ case 'O': {
+ int ref = readInt();
+ int size = _classDefs.size();
+
+ if (ref < 0 || size <= ref)
+ throw new HessianProtocolException("'" + ref + "' is an unknown class definition");
+
+ ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+
+ return readObjectInstance(expectedClass, def);
+ }
+
+ case BC_LIST_VARIABLE: {
+ String type = readType();
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(type, expectedClass);
+
+ Object v = reader.readList(this, -1);
+
+ return v;
+ }
+
+ case BC_LIST_FIXED: {
+ String type = readType();
+ int length = readInt();
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(type, expectedClass);
+
+ boolean valueType = expectedTypes != null && expectedTypes.length == 1;
+
+ Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+
+ return v;
+ }
+
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77: {
+ int length = tag - 0x70;
+
+ String type = readType();
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+
+ boolean valueType = expectedTypes != null && expectedTypes.length == 1;
+
+ // fix deserialize of short type
+ Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+
+ return v;
+ }
+
+ case BC_LIST_VARIABLE_UNTYPED: {
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+
+ boolean valueType = expectedTypes != null && expectedTypes.length == 1;
+
+ // fix deserialize of short type
+ Object v = reader.readList(this, -1, valueType ? expectedTypes[0] : null);
+
+ return v;
+ }
+
+ case BC_LIST_FIXED_UNTYPED: {
+ int length = readInt();
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+
+ boolean valueType = expectedTypes != null && expectedTypes.length == 1;
+
+ // fix deserialize of short type
+ Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+
+ return v;
+ }
+
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f: {
+ int length = tag - 0x78;
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(null, expectedClass);
+
+ boolean valueType = expectedTypes != null && expectedTypes.length == 1;
+
+ // fix deserialize of short type
+ Object v = reader.readLengthList(this, length, valueType ? expectedTypes[0] : null);
+
+ return v;
+ }
+
+ case BC_REF: {
+ int ref = readInt();
+
+ return _refs.get(ref);
+ }
+ }
+
+ if (tag >= 0)
+ _offset--;
+
+ // hessian/3b2i vs hessian/3406
+ // return readObject();
+ Object value = findSerializerFactory().getDeserializer(expectedClass).readObject(this);
+ return value;
+ }
+
+ /**
+ * Reads an arbitrary object from the input stream when the type
+ * is unknown.
+ */
+ @Override
+ public Object readObject()
+ throws IOException {
+ return readObject((List<Class<?>>) null);
+ }
+
+ @Override
+ public Object readObject(List<Class<?>> expectedTypes) throws IOException {
+ int tag = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ switch (tag) {
+ case 'N':
+ return null;
+
+ case 'T':
+ return Boolean.valueOf(true);
+
+ case 'F':
+ return Boolean.valueOf(false);
+
+ // direct integer
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ return Integer.valueOf(tag - BC_INT_ZERO);
+
+ /* byte int */
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ case 0xc6:
+ case 0xc7:
+ case 0xc8:
+ case 0xc9:
+ case 0xca:
+ case 0xcb:
+ case 0xcc:
+ case 0xcd:
+ case 0xce:
+ case 0xcf:
+ return Integer.valueOf(((tag - BC_INT_BYTE_ZERO) << 8) + read());
+
+ /* short int */
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ case 0xd4:
+ case 0xd5:
+ case 0xd6:
+ case 0xd7:
+ return Integer.valueOf(((tag - BC_INT_SHORT_ZERO) << 16)
+ + 256 * read() + read());
+
+ case 'I':
+ return Integer.valueOf(parseInt());
+
+ // direct long
+ case 0xd8:
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ return Long.valueOf(tag - BC_LONG_ZERO);
+
+ /* byte long */
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ return Long.valueOf(((tag - BC_LONG_BYTE_ZERO) << 8) + read());
+
+ /* short long */
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ return Long.valueOf(((tag - BC_LONG_SHORT_ZERO) << 16) + 256 * read() + read());
+
+ case BC_LONG_INT:
+ return Long.valueOf(parseInt());
+
+ case 'L':
+ return Long.valueOf(parseLong());
+
+ case BC_DOUBLE_ZERO:
+ return Double.valueOf(0);
+
+ case BC_DOUBLE_ONE:
+ return Double.valueOf(1);
+
+ case BC_DOUBLE_BYTE:
+ return Double.valueOf((byte) read());
+
+ case BC_DOUBLE_SHORT:
+ return Double.valueOf((short) (256 * read() + read()));
+
+ case BC_DOUBLE_MILL: {
+ int mills = parseInt();
+
+ return Double.valueOf(0.001 * mills);
+ }
+
+ case 'D':
+ return Double.valueOf(parseDouble());
+
+ case BC_DATE:
+ return new Date(parseLong());
+
+ case BC_DATE_MINUTE:
+ return new Date(parseInt() * 60000L);
+
+ case BC_STRING_CHUNK:
+ case 'S': {
+ _isLastChunk = tag == 'S';
+ _chunkLength = (read() << 8) + read();
+
+ _sbuf.setLength(0);
+
+ parseString(_sbuf);
+
+ return _sbuf.toString();
+ }
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f: {
+ _isLastChunk = true;
+ _chunkLength = tag - 0x00;
+
+ _sbuf.setLength(0);
+
+ parseString(_sbuf);
+
+ return _sbuf.toString();
+ }
+
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33: {
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x30) * 256 + read();
+
+ _sbuf.setLength(0);
+
+ parseString(_sbuf);
+
+ return _sbuf.toString();
+ }
+
+ case BC_BINARY_CHUNK:
+ case 'B': {
+ _isLastChunk = tag == 'B';
+ _chunkLength = (read() << 8) + read();
+
+ int data;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ while ((data = parseByte()) >= 0)
+ bos.write(data);
+
+ return bos.toByteArray();
+ }
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f: {
+ _isLastChunk = true;
+ int len = tag - 0x20;
+ _chunkLength = 0;
+
+ byte[] data = new byte[len];
+
+ for (int i = 0; i < len; i++)
+ data[i] = (byte) read();
+
+ return data;
+ }
+
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37: {
+ _isLastChunk = true;
+ int len = (tag - 0x34) * 256 + read();
+ _chunkLength = 0;
+
+ byte[] buffer = new byte[len];
+
+ for (int i = 0; i < len; i++) {
+ buffer[i] = (byte) read();
+ }
+
+ return buffer;
+ }
+
+ case BC_LIST_VARIABLE: {
+ // variable length list
+ String type = readType();
+
+ return findSerializerFactory().readList(this, -1, type);
+ }
+
+ case BC_LIST_VARIABLE_UNTYPED: {
+ return findSerializerFactory().readList(this, -1, null);
+ }
+
+ case BC_LIST_FIXED: {
+ // fixed length lists
+ String type = readType();
+ int length = readInt();
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(type, null);
+
+ boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
+
+ return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ }
+
+ case BC_LIST_FIXED_UNTYPED: {
+ // fixed length lists
+ int length = readInt();
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(null, null);
+
+ boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
+
+ return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ }
+
+ // compact fixed list
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77: {
+ // fixed length lists
+ String type = readType();
+ int length = tag - 0x70;
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(type, null);
+
+ boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
+
+ return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ }
+
+ // compact fixed untyped list
+ case 0x78:
+ case 0x79:
+ case 0x7a:
+ case 0x7b:
+ case 0x7c:
+ case 0x7d:
+ case 0x7e:
+ case 0x7f: {
+ // fixed length lists
+ int length = tag - 0x78;
+
+ Deserializer reader;
+ reader = findSerializerFactory().getListDeserializer(null, null);
+
+ boolean valueType = expectedTypes != null && expectedTypes.size() == 1;
+
+ return reader.readLengthList(this, length, valueType ? expectedTypes.get(0) : null);
+ }
+
+ case 'H': {
+
+ boolean keyValuePair = expectedTypes != null && expectedTypes.size() == 2;
+
+ // fix deserialize of short type
+ Deserializer reader;
+ reader = findSerializerFactory().getDeserializer(Map.class);
+
+ return reader.readMap(this
+ , keyValuePair ? expectedTypes.get(0) : null
+ , keyValuePair ? expectedTypes.get(1) : null);
+ }
+
+ case 'M': {
+ String type = readType();
+
+ return findSerializerFactory().readMap(this, type);
+ }
+
+ case 'C': {
+ readObjectDefinition(null);
+
+ return readObject();
+ }
+
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f: {
+ int ref = tag - 0x60;
+
+ if (_classDefs == null)
+ throw error("No classes defined at reference '{0}'" + tag);
+
+ ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+
+ return readObjectInstance(null, def);
+ }
+
+ case 'O': {
+ int ref = readInt();
+
+ ObjectDefinition def = (ObjectDefinition) _classDefs.get(ref);
+
+ return readObjectInstance(null, def);
+ }
+
+ case BC_REF: {
+ int ref = readInt();
+
+ return _refs.get(ref);
+ }
+
+ default:
+ if (tag < 0)
+ throw new EOFException("readObject: unexpected end of file");
+ else
+ throw error("readObject: unknown code " + codeName(tag));
+ }
+ }
+
+ private void parseString(StringBuilder sbuf)
+ throws IOException {
+ while (true) {
+ if (_chunkLength <= 0) {
+ if (!parseChunkLength())
+ return;
+ }
+
+ int length = _chunkLength;
+ _chunkLength = 0;
+
+ while (length-- > 0) {
+ sbuf.append((char) parseUTF8Char());
+ }
+ }
+ }
+
+ /**
+ * Reads an object definition:
+ * <p>
+ * <pre>
+ * O string <int> (string)* <value>*
+ * </pre>
+ */
+ private void readObjectDefinition(Class cl)
+ throws IOException {
+ String type = readString();
+ int len = readInt();
+
+ String[] fieldNames = new String[len];
+ for (int i = 0; i < len; i++)
+ fieldNames[i] = readString();
+
+ ObjectDefinition def = new ObjectDefinition(type, fieldNames);
+
+ if (_classDefs == null)
+ _classDefs = new ArrayList();
+
+ _classDefs.add(def);
+ }
+
+ private Object readObjectInstance(Class cl, ObjectDefinition def)
+ throws IOException {
+ String type = def.getType();
+ String[] fieldNames = def.getFieldNames();
+
+ if (cl != null) {
+ Deserializer reader;
+ reader = findSerializerFactory().getObjectDeserializer(type, cl);
+
+ return reader.readObject(this, fieldNames);
+ } else {
+ return findSerializerFactory().readObject(this, type, fieldNames);
+ }
+ }
+
+ private String readLenString()
+ throws IOException {
+ int len = readInt();
+
+ _isLastChunk = true;
+ _chunkLength = len;
+
+ _sbuf.setLength(0);
+ int ch;
+ while ((ch = parseChar()) >= 0)
+ _sbuf.append((char) ch);
+
+ return _sbuf.toString();
+ }
+
+ private String readLenString(int len)
+ throws IOException {
+ _isLastChunk = true;
+ _chunkLength = len;
+
+ _sbuf.setLength(0);
+ int ch;
+ while ((ch = parseChar()) >= 0)
+ _sbuf.append((char) ch);
+
+ return _sbuf.toString();
+ }
+
+ /**
+ * Reads a remote object.
+ */
+ @Override
+ public Object readRemote()
+ throws IOException {
+ String type = readType();
+ String url = readString();
+
+ return resolveRemote(type, url);
+ }
+
+ /**
+ * Reads a reference.
+ */
+ @Override
+ public Object readRef()
+ throws IOException {
+ return _refs.get(parseInt());
+ }
+
+ /**
+ * Reads the start of a list.
+ */
+ @Override
+ public int readListStart()
+ throws IOException {
+ return read();
+ }
+
+ /**
+ * Reads the start of a list.
+ */
+ @Override
+ public int readMapStart()
+ throws IOException {
+ return read();
+ }
+
+ /**
+ * Returns true if this is the end of a list or a map.
+ */
+ @Override
+ public boolean isEnd()
+ throws IOException {
+ int code;
+
+ if (_offset < _length)
+ code = (_buffer[_offset] & 0xff);
+ else {
+ code = read();
+
+ if (code >= 0)
+ _offset--;
+ }
+
+ return (code < 0 || code == 'Z');
+ }
+
+ /**
+ * Reads the end byte.
+ */
+ @Override
+ public void readEnd()
+ throws IOException {
+ int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ if (code == 'Z')
+ return;
+ else if (code < 0)
+ throw error("unexpected end of file");
+ else
+ throw error("unknown code:" + codeName(code));
+ }
+
+ /**
+ * Reads the end byte.
+ */
+ @Override
+ public void readMapEnd()
+ throws IOException {
+ int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ if (code != 'Z')
+ throw error("expected end of map ('Z') at '" + codeName(code) + "'");
+ }
+
+ /**
+ * Reads the end byte.
+ */
+ @Override
+ public void readListEnd()
+ throws IOException {
+ int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ if (code != 'Z')
+ throw error("expected end of list ('Z') at '" + codeName(code) + "'");
+ }
+
+ /**
+ * Adds a list/map reference.
+ */
+ @Override
+ public int addRef(Object ref) {
+ if (_refs == null)
+ _refs = new ArrayList();
+
+ _refs.add(ref);
+
+ return _refs.size() - 1;
+ }
+
+ /**
+ * Adds a list/map reference.
+ */
+ @Override
+ public void setRef(int i, Object ref) {
+ _refs.set(i, ref);
+ }
+
+ /**
+ * Resets the references for streaming.
+ */
+ @Override
+ public void resetReferences() {
+ if (_refs != null)
+ _refs.clear();
+ }
+
+ public Object readStreamingObject()
+ throws IOException {
+ if (_refs != null)
+ _refs.clear();
+
+ return readObject();
+ }
+
+ /**
+ * Resolves a remote object.
+ */
+ public Object resolveRemote(String type, String url)
+ throws IOException {
+ HessianRemoteResolver resolver = getRemoteResolver();
+
+ if (resolver != null)
+ return resolver.lookup(type, url);
+ else
+ return new HessianRemote(type, url);
+ }
+
+ /**
+ * Parses a type from the stream.
+ * <p>
+ * <pre>
+ * type ::= string
+ * type ::= int
+ * </pre>
+ */
+ @Override
+ public String readType()
+ throws IOException {
+ int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+ _offset--;
+
+ switch (code) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case BC_STRING_CHUNK:
+ case 'S': {
+ String type = readString();
+
+ if (_types == null)
+ _types = new ArrayList();
+
+ _types.add(type);
+
+ return type;
+ }
+
+ default: {
+ int ref = readInt();
+
+ if (_types.size() <= ref)
+ throw new IndexOutOfBoundsException("type ref #" + ref + " is greater than the number of valid types (" + _types.size() + ")");
+
+ return (String) _types.get(ref);
+ }
+ }
+ }
+
+ /**
+ * Parses the length for an array
+ * <p>
+ * <pre>
+ * l b32 b24 b16 b8
+ * </pre>
+ */
+ @Override
+ public int readLength()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Parses a 32-bit integer value from the stream.
+ * <p>
+ * <pre>
+ * b32 b24 b16 b8
+ * </pre>
+ */
+ private int parseInt()
+ throws IOException {
+ int offset = _offset;
+
+ if (offset + 3 < _length) {
+ byte[] buffer = _buffer;
+
+ int b32 = buffer[offset + 0] & 0xff;
+ int b24 = buffer[offset + 1] & 0xff;
+ int b16 = buffer[offset + 2] & 0xff;
+ int b8 = buffer[offset + 3] & 0xff;
+
+ _offset = offset + 4;
+
+ return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
+ } else {
+ int b32 = read();
+ int b24 = read();
+ int b16 = read();
+ int b8 = read();
+
+ return (b32 << 24) + (b24 << 16) + (b16 << 8) + b8;
+ }
+ }
+
+ /**
+ * Parses a 64-bit long value from the stream.
+ * <p>
+ * <pre>
+ * b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ private long parseLong()
+ throws IOException {
+ long b64 = read();
+ long b56 = read();
+ long b48 = read();
+ long b40 = read();
+ long b32 = read();
+ long b24 = read();
+ long b16 = read();
+ long b8 = read();
+
+ return ((b64 << 56)
+ + (b56 << 48)
+ + (b48 << 40)
+ + (b40 << 32)
+ + (b32 << 24)
+ + (b24 << 16)
+ + (b16 << 8)
+ + b8);
+ }
+
+ /**
+ * Parses a 64-bit double value from the stream.
+ * <p>
+ * <pre>
+ * b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre>
+ */
+ private double parseDouble()
+ throws IOException {
+ long bits = parseLong();
+
+ return Double.longBitsToDouble(bits);
+ }
+
+ org.w3c.dom.Node parseXML()
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ private boolean parseChunkLength()
+ throws IOException {
+ if (_isLastChunk)
+ return false;
+
+ int code = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ switch (code) {
+ case BC_STRING_CHUNK:
+ _isLastChunk = false;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 'S':
+ _isLastChunk = true;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f:
+ _isLastChunk = true;
+ _chunkLength = code - 0x00;
+ break;
+
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ _isLastChunk = true;
+ _chunkLength = (code - 0x30) * 256 + read();
+ break;
+
+ default:
+ throw expect("string", code);
+ }
+
+ return true;
+ }
+
+ /**
+ * Reads a character from the underlying stream.
+ */
+ private int parseChar()
+ throws IOException {
+ while (_chunkLength <= 0) {
+ if (!parseChunkLength())
+ return -1;
+ }
+
+ _chunkLength--;
+
+ return parseUTF8Char();
+ }
+
+ /**
+ * Parses a single UTF8 character.
+ */
+ private int parseUTF8Char()
+ throws IOException {
+ int ch = _offset < _length ? (_buffer[_offset++] & 0xff) : read();
+
+ if (ch < 0x80)
+ return ch;
+ else if ((ch & 0xe0) == 0xc0) {
+ int ch1 = read();
+ int v = ((ch & 0x1f) << 6) + (ch1 & 0x3f);
+
+ return v;
+ } else if ((ch & 0xf0) == 0xe0) {
+ int ch1 = read();
+ int ch2 = read();
+ int v = ((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f);
+
+ return v;
+ } else
+ throw error("bad utf-8 encoding at " + codeName(ch));
+ }
+
+ /**
+ * Reads a byte from the underlying stream.
+ */
+ private int parseByte()
+ throws IOException {
+ while (_chunkLength <= 0) {
+ if (_isLastChunk) {
+ return -1;
+ }
+
+ int code = read();
+
+ switch (code) {
+ case BC_BINARY_CHUNK:
+ _isLastChunk = false;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 'B':
+ _isLastChunk = true;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ _isLastChunk = true;
+
+ _chunkLength = code - 0x20;
+ break;
+
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ _isLastChunk = true;
+ _chunkLength = (code - 0x34) * 256 + read();
+ break;
+
+ default:
+ throw expect("byte[]", code);
+ }
+ }
+
+ _chunkLength--;
+
+ return read();
+ }
+
+ /**
+ * Reads bytes based on an input stream.
+ */
+ @Override
+ public InputStream readInputStream()
+ throws IOException {
+ int tag = read();
+
+ switch (tag) {
+ case 'N':
+ return null;
+
+ case BC_BINARY:
+ case BC_BINARY_CHUNK:
+ case 'b': //maybe it's a mistype of BC_BINARY_CHUNK
+ _isLastChunk = tag == 'B';
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ _isLastChunk = true;
+ _chunkLength = tag - 0x20;
+ break;
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ _isLastChunk = true;
+ _chunkLength = (tag - 0x34) * 256 + read();
+ break;
+ default:
+ throw expect("binary", tag);
+ }
+
+ return new ReadInputStream();
+ }
+
+ /**
+ * Reads bytes from the underlying stream.
+ */
+ int read(byte[] buffer, int offset, int length)
+ throws IOException {
+ int readLength = 0;
+
+ while (length > 0) {
+ while (_chunkLength <= 0) {
+ if (_isLastChunk)
+ return readLength == 0 ? -1 : readLength;
+
+ int code = read();
+
+ switch (code) {
+ case BC_BINARY_CHUNK:
+ case 'b': //maybe it's a mistype of BC_BINARY_CHUNK
+ _isLastChunk = false;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case BC_BINARY:
+ _isLastChunk = true;
+
+ _chunkLength = (read() << 8) + read();
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ _isLastChunk = true;
+ _chunkLength = code - 0x20;
+ break;
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ _isLastChunk = true;
+ _chunkLength = (code - 0x34) * 256 + read();
+ break;
+ default:
+ throw expect("byte[]", code);
+ }
+ }
+
+ int sublen = _chunkLength;
+ if (length < sublen)
+ sublen = length;
+
+ if (_length <= _offset && !readBuffer())
+ return -1;
+
+ if (_length - _offset < sublen)
+ sublen = _length - _offset;
+
+ System.arraycopy(_buffer, _offset, buffer, offset, sublen);
+
+ _offset += sublen;
+
+ offset += sublen;
+ readLength += sublen;
+ length -= sublen;
+ _chunkLength -= sublen;
+ }
+
+ return readLength;
+ }
+
+ /**
+ * Normally, shouldn't be called externally, but needed for QA, e.g.
+ * ejb/3b01.
+ */
+ public final int read()
+ throws IOException {
+ if (_length <= _offset && !readBuffer())
+ return -1;
+
+ return _buffer[_offset++] & 0xff;
+ }
+
+ private final boolean readBuffer()
+ throws IOException {
+ byte[] buffer = _buffer;
+ int offset = _offset;
+ int length = _length;
+
+ if (offset < length) {
+ System.arraycopy(buffer, offset, buffer, 0, length - offset);
+ offset = length - offset;
+ } else
+ offset = 0;
+
+ int len = _is.read(buffer, offset, SIZE - offset);
+
+ if (len <= 0) {
+ _length = offset;
+ _offset = 0;
+
+ return offset > 0;
+ }
+
+ _length = offset + len;
+ _offset = 0;
+
+ return true;
+ }
+
+ @Override
+ public Reader getReader() {
+ return null;
+ }
+
+ protected IOException expect(String expect, int ch)
+ throws IOException {
+ if (ch < 0)
+ return error("expected " + expect + " at end of file");
+ else {
+ _offset--;
+
+ try {
+ Object obj = readObject();
+
+ if (obj != null) {
+ return error("expected " + expect
+ + " at 0x" + Integer.toHexString(ch & 0xff)
+ + " " + obj.getClass().getName());
+ } else
+ return error("expected " + expect
+ + " at 0x" + Integer.toHexString(ch & 0xff) + " null");
+ } catch (IOException e) {
+ log.log(Level.FINE, e.toString(), e);
+
+ return error("expected " + expect
+ + " at 0x" + Integer.toHexString(ch & 0xff));
+ }
+ }
+ }
+
+ protected String codeName(int ch) {
+ if (ch < 0)
+ return "end of file";
+ else
+ return "0x" + Integer.toHexString(ch & 0xff) + " (" + (char) +ch + ")";
+ }
+
+ protected IOException error(String message) {
+ if (_method != null)
+ return new HessianProtocolException(_method + ": " + message);
+ else
+ return new HessianProtocolException(message);
+ }
+
+ @Override
+ public void close()
+ throws IOException {
+ InputStream is = _is;
+ _is = null;
+
+ if (_isCloseStreamOnClose && is != null)
+ is.close();
+ }
+
+ ;
+
+ final static class ObjectDefinition {
+ private final String _type;
+ private final String[] _fields;
+
+ ObjectDefinition(String type, String[] fields) {
+ _type = type;
+ _fields = fields;
+ }
+
+ String getType() {
+ return _type;
+ }
+
+ String[] getFieldNames() {
+ return _fields;
+ }
+ }
+
+ class ReadInputStream extends InputStream {
+ boolean _isClosed = false;
+
+ @Override
+ public int read()
+ throws IOException {
+ if (_isClosed)
+ return -1;
+
+ int ch = parseByte();
+ if (ch < 0)
+ _isClosed = true;
+
+ return ch;
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int length)
+ throws IOException {
+ if (_isClosed)
+ return -1;
+
+ int len = Hessian2Input.this.read(buffer, offset, length);
+ if (len < 0)
+ _isClosed = true;
+
+ return len;
+ }
+
+ @Override
+ public void close()
+ throws IOException {
+ while (read() >= 0) {
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Output.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Output.java
new file mode 100644
index 0000000..2bb575c
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2Output.java
@@ -0,0 +1,1558 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import com.alibaba.com.caucho.hessian3.util.IdentityIntMap;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+
+/**
+ * Output stream for Hessian 2 requests.
+ * <p>
+ * <p>Since HessianOutput does not depend on any classes other than
+ * in the JDK, it can be extracted independently into a smaller package.
+ * <p>
+ * <p>HessianOutput is unbuffered, so any client needs to provide
+ * its own buffering.
+ * <p>
+ * <pre>
+ * OutputStream os = ...; // from http connection
+ * Hessian2Output out = new Hessian2Output(os);
+ * String value;
+ *
+ * out.startCall("hello", 1); // start hello call
+ * out.writeString("arg1"); // write a string argument
+ * out.completeCall(); // complete the call
+ * </pre>
+ */
+public class Hessian2Output
+ extends AbstractHessianOutput
+ implements Hessian2Constants {
+ public final static int SIZE = 4096;
+ private final byte[] _buffer = new byte[SIZE];
+ // the output stream/
+ protected OutputStream _os;
+ // map of references
+ private IdentityIntMap _refs = new IdentityIntMap();
+ private boolean _isCloseStreamOnClose;
+ // map of classes
+ private HashMap _classRefs;
+ // map of types
+ private HashMap _typeRefs;
+ private int _offset;
+
+ private boolean _isStreaming;
+
+ /**
+ * Creates a new Hessian output stream, initialized with an
+ * underlying output stream.
+ *
+ * @param os the underlying output stream.
+ */
+ public Hessian2Output(OutputStream os) {
+ _os = os;
+ }
+
+ @Override
+ public void init(OutputStream os) {
+ reset();
+
+ _os = os;
+ }
+
+ /**
+ * Resets all counters and references
+ */
+ public void reset() {
+ resetReferences();
+
+ if (_classRefs != null) {
+ _classRefs.clear();
+ }
+
+ if (_typeRefs != null) {
+ _typeRefs.clear();
+ }
+
+ _offset = 0;
+ }
+
+ public boolean isCloseStreamOnClose() {
+ return _isCloseStreamOnClose;
+ }
+
+ public void setCloseStreamOnClose(boolean isClose) {
+ _isCloseStreamOnClose = isClose;
+ }
+
+ /**
+ * Writes a complete method call.
+ */
+ @Override
+ public void call(String method, Object[] args)
+ throws IOException {
+ int length = args != null ? args.length : 0;
+
+ startCall(method, length);
+
+ for (int i = 0; i < args.length; i++)
+ writeObject(args[i]);
+
+ completeCall();
+ }
+
+ /**
+ * Starts the method call. Clients would use <code>startCall</code>
+ * instead of <code>call</code> if they wanted finer control over
+ * writing the arguments, or needed to write headers.
+ * <p>
+ * <code><pre>
+ * C
+ * string # method name
+ * int # arg count
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ @Override
+ public void startCall(String method, int length)
+ throws IOException {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ flush();
+ offset = _offset;
+ }
+
+ byte[] buffer = _buffer;
+
+ buffer[_offset++] = (byte) 'C';
+
+ writeString(method);
+ writeInt(length);
+ }
+
+ /**
+ * Writes the call tag. This would be followed by the
+ * method and the arguments
+ * <p>
+ * <code><pre>
+ * C
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ @Override
+ public void startCall()
+ throws IOException {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'C';
+ }
+
+ /**
+ * Starts an envelope.
+ * <p>
+ * <code><pre>
+ * E major minor
+ * m b16 b8 method-name
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ public void startEnvelope(String method)
+ throws IOException {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ flush();
+ offset = _offset;
+ }
+
+ _buffer[_offset++] = (byte) 'E';
+
+ writeString(method);
+ }
+
+ /**
+ * Completes an envelope.
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * Z
+ * </pre>
+ */
+ public void completeEnvelope()
+ throws IOException {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'Z';
+ }
+
+ /**
+ * Writes the method tag.
+ * <p>
+ * <code><pre>
+ * string
+ * </pre></code>
+ *
+ * @param method the method name to call.
+ */
+ @Override
+ public void writeMethod(String method)
+ throws IOException {
+ writeString(method);
+ }
+
+ /**
+ * Completes.
+ * <p>
+ * <code><pre>
+ * z
+ * </pre></code>
+ */
+ @Override
+ public void completeCall()
+ throws IOException {
+ /*
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'Z';
+ */
+ }
+
+ /**
+ * Starts the reply
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * R
+ * </pre>
+ */
+ @Override
+ public void startReply()
+ throws IOException {
+ writeVersion();
+
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'R';
+ }
+
+ public void writeVersion()
+ throws IOException {
+ flushIfFull();
+ _buffer[_offset++] = (byte) 'H';
+ _buffer[_offset++] = (byte) 2;
+ _buffer[_offset++] = (byte) 0;
+ }
+
+ /**
+ * Completes reading the reply
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * z
+ * </pre>
+ */
+ @Override
+ public void completeReply()
+ throws IOException {
+ }
+
+ /**
+ * Starts a packet
+ * <p>
+ * <p>A message contains several objects encapsulated by a length</p>
+ * <p>
+ * <pre>
+ * p x02 x00
+ * </pre>
+ */
+ public void startMessage()
+ throws IOException {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'p';
+ _buffer[_offset++] = (byte) 2;
+ _buffer[_offset++] = (byte) 0;
+ }
+
+ /**
+ * Completes reading the message
+ * <p>
+ * <p>A successful completion will have a single value:
+ * <p>
+ * <pre>
+ * z
+ * </pre>
+ */
+ public void completeMessage()
+ throws IOException {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) 'z';
+ }
+
+ /**
+ * Writes a fault. The fault will be written
+ * as a descriptive string followed by an object:
+ * <p>
+ * <code><pre>
+ * F map
+ * </pre></code>
+ * <p>
+ * <code><pre>
+ * F H
+ * \x04code
+ * \x10the fault code
+ * <p>
+ * \x07message
+ * \x11the fault message
+ * <p>
+ * \x06detail
+ * M\xnnjavax.ejb.FinderException
+ * ...
+ * Z
+ * Z
+ * </pre></code>
+ *
+ * @param code the fault code, a three digit
+ */
+ @Override
+ public void writeFault(String code, String message, Object detail)
+ throws IOException {
+ flushIfFull();
+
+ writeVersion();
+
+ _buffer[_offset++] = (byte) 'F';
+ _buffer[_offset++] = (byte) 'H';
+
+ _refs.put(new HashMap(), _refs.size());
+
+ writeString("code");
+ writeString(code);
+
+ writeString("message");
+ writeString(message);
+
+ if (detail != null) {
+ writeString("detail");
+ writeObject(detail);
+ }
+
+ flushIfFull();
+ _buffer[_offset++] = (byte) 'Z';
+ }
+
+ /**
+ * Writes any object to the output stream.
+ */
+ @Override
+ public void writeObject(Object object)
+ throws IOException {
+ if (object == null) {
+ writeNull();
+ return;
+ }
+
+ Serializer serializer = findSerializerFactory().getSerializer(object.getClass());
+ serializer.writeObject(object, this);
+ }
+
+ /**
+ * Writes the list header to the stream. List writers will call
+ * <code>writeListBegin</code> followed by the list contents and then
+ * call <code>writeListEnd</code>.
+ * <p>
+ * <code><pre>
+ * list ::= V type value* Z
+ * ::= v type int value*
+ * </pre></code>
+ *
+ * @return true for variable lists, false for fixed lists
+ */
+ @Override
+ public boolean writeListBegin(int length, String type)
+ throws IOException {
+ flushIfFull();
+
+ if (length < 0) {
+ if (type != null) {
+ _buffer[_offset++] = (byte) BC_LIST_VARIABLE;
+ writeType(type);
+ } else
+ _buffer[_offset++] = (byte) BC_LIST_VARIABLE_UNTYPED;
+
+ return true;
+ } else if (length <= LIST_DIRECT_MAX) {
+ if (type != null) {
+ _buffer[_offset++] = (byte) (BC_LIST_DIRECT + length);
+ writeType(type);
+ } else {
+ _buffer[_offset++] = (byte) (BC_LIST_DIRECT_UNTYPED + length);
+ }
+
+ return false;
+ } else {
+ if (type != null) {
+ _buffer[_offset++] = (byte) BC_LIST_FIXED;
+ writeType(type);
+ } else {
+ _buffer[_offset++] = (byte) BC_LIST_FIXED_UNTYPED;
+ }
+
+ writeInt(length);
+
+ return false;
+ }
+ }
+
+ /**
+ * Writes the tail of the list to the stream for a variable-length list.
+ */
+ @Override
+ public void writeListEnd()
+ throws IOException {
+ flushIfFull();
+
+ _buffer[_offset++] = (byte) BC_END;
+ }
+
+ /**
+ * Writes the map header to the stream. Map writers will call
+ * <code>writeMapBegin</code> followed by the map contents and then
+ * call <code>writeMapEnd</code>.
+ * <p>
+ * <code><pre>
+ * map ::= M type (<value> <value>)* Z
+ * ::= H (<value> <value>)* Z
+ * </pre></code>
+ */
+ @Override
+ public void writeMapBegin(String type)
+ throws IOException {
+ if (SIZE < _offset + 32)
+ flush();
+
+ if (type != null) {
+ _buffer[_offset++] = BC_MAP;
+
+ writeType(type);
+ } else
+ _buffer[_offset++] = BC_MAP_UNTYPED;
+ }
+
+ /**
+ * Writes the tail of the map to the stream.
+ */
+ @Override
+ public void writeMapEnd()
+ throws IOException {
+ if (SIZE < _offset + 32)
+ flush();
+
+ _buffer[_offset++] = (byte) BC_END;
+ }
+
+ /**
+ * Writes the object definition
+ * <p>
+ * <code><pre>
+ * C <string> <int> <string>*
+ * </pre></code>
+ */
+ @Override
+ public int writeObjectBegin(String type)
+ throws IOException {
+ if (_classRefs == null)
+ _classRefs = new HashMap();
+
+ Integer refV = (Integer) _classRefs.get(type);
+
+ if (refV != null) {
+ int ref = refV.intValue();
+
+ if (SIZE < _offset + 32)
+ flush();
+
+ if (ref <= OBJECT_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_OBJECT_DIRECT + ref);
+ } else {
+ _buffer[_offset++] = (byte) 'O';
+ writeInt(ref);
+ }
+
+ return ref;
+ } else {
+ int ref = _classRefs.size();
+
+ _classRefs.put(type, Integer.valueOf(ref));
+
+ if (SIZE < _offset + 32)
+ flush();
+
+ _buffer[_offset++] = (byte) 'C';
+
+ writeString(type);
+
+ return -1;
+ }
+ }
+
+ /**
+ * Writes the tail of the class definition to the stream.
+ */
+ @Override
+ public void writeClassFieldLength(int len)
+ throws IOException {
+ writeInt(len);
+ }
+
+ /**
+ * Writes the tail of the object definition to the stream.
+ */
+ @Override
+ public void writeObjectEnd()
+ throws IOException {
+ }
+
+ /**
+ * <code><pre>
+ * type ::= string
+ * ::= int
+ * </code></pre>
+ */
+ private void writeType(String type)
+ throws IOException {
+ flushIfFull();
+
+ int len = type.length();
+ if (len == 0) {
+ throw new IllegalArgumentException("empty type is not allowed");
+ }
+
+ if (_typeRefs == null)
+ _typeRefs = new HashMap();
+
+ Integer typeRefV = (Integer) _typeRefs.get(type);
+
+ if (typeRefV != null) {
+ int typeRef = typeRefV.intValue();
+
+ writeInt(typeRef);
+ } else {
+ _typeRefs.put(type, Integer.valueOf(_typeRefs.size()));
+
+ writeString(type);
+ }
+ }
+
+ /**
+ * Writes a boolean value to the stream. The boolean will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * T
+ * F
+ * </pre></code>
+ *
+ * @param value the boolean value to write.
+ */
+ @Override
+ public void writeBoolean(boolean value)
+ throws IOException {
+ if (SIZE < _offset + 16)
+ flush();
+
+ if (value)
+ _buffer[_offset++] = (byte) 'T';
+ else
+ _buffer[_offset++] = (byte) 'F';
+ }
+
+ /**
+ * Writes an integer value to the stream. The integer will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * I b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param value the integer value to write.
+ */
+ @Override
+ public void writeInt(int value)
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX)
+ buffer[offset++] = (byte) (value + BC_INT_ZERO);
+ else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) {
+ buffer[offset++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8));
+ buffer[offset++] = (byte) (value);
+ } else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) {
+ buffer[offset++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16));
+ buffer[offset++] = (byte) (value >> 8);
+ buffer[offset++] = (byte) (value);
+ } else {
+ buffer[offset++] = (byte) ('I');
+ buffer[offset++] = (byte) (value >> 24);
+ buffer[offset++] = (byte) (value >> 16);
+ buffer[offset++] = (byte) (value >> 8);
+ buffer[offset++] = (byte) (value);
+ }
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a long value to the stream. The long will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * L b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param value the long value to write.
+ */
+ @Override
+ public void writeLong(long value)
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (LONG_DIRECT_MIN <= value && value <= LONG_DIRECT_MAX) {
+ buffer[offset++] = (byte) (value + BC_LONG_ZERO);
+ } else if (LONG_BYTE_MIN <= value && value <= LONG_BYTE_MAX) {
+ buffer[offset++] = (byte) (BC_LONG_BYTE_ZERO + (value >> 8));
+ buffer[offset++] = (byte) (value);
+ } else if (LONG_SHORT_MIN <= value && value <= LONG_SHORT_MAX) {
+ buffer[offset++] = (byte) (BC_LONG_SHORT_ZERO + (value >> 16));
+ buffer[offset++] = (byte) (value >> 8);
+ buffer[offset++] = (byte) (value);
+ } else if (-0x80000000L <= value && value <= 0x7fffffffL) {
+ buffer[offset + 0] = (byte) BC_LONG_INT;
+ buffer[offset + 1] = (byte) (value >> 24);
+ buffer[offset + 2] = (byte) (value >> 16);
+ buffer[offset + 3] = (byte) (value >> 8);
+ buffer[offset + 4] = (byte) (value);
+
+ offset += 5;
+ } else {
+ buffer[offset + 0] = (byte) 'L';
+ buffer[offset + 1] = (byte) (value >> 56);
+ buffer[offset + 2] = (byte) (value >> 48);
+ buffer[offset + 3] = (byte) (value >> 40);
+ buffer[offset + 4] = (byte) (value >> 32);
+ buffer[offset + 5] = (byte) (value >> 24);
+ buffer[offset + 6] = (byte) (value >> 16);
+ buffer[offset + 7] = (byte) (value >> 8);
+ buffer[offset + 8] = (byte) (value);
+
+ offset += 9;
+ }
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a double value to the stream. The double will be written
+ * with the following syntax:
+ * <p>
+ * <code><pre>
+ * D b64 b56 b48 b40 b32 b24 b16 b8
+ * </pre></code>
+ *
+ * @param value the double value to write.
+ */
+ @Override
+ public void writeDouble(double value)
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ int intValue = (int) value;
+
+ if (intValue == value) {
+ if (intValue == 0) {
+ buffer[offset++] = (byte) BC_DOUBLE_ZERO;
+
+ _offset = offset;
+
+ return;
+ } else if (intValue == 1) {
+ buffer[offset++] = (byte) BC_DOUBLE_ONE;
+
+ _offset = offset;
+
+ return;
+ } else if (-0x80 <= intValue && intValue < 0x80) {
+ buffer[offset++] = (byte) BC_DOUBLE_BYTE;
+ buffer[offset++] = (byte) intValue;
+
+ _offset = offset;
+
+ return;
+ } else if (-0x8000 <= intValue && intValue < 0x8000) {
+ buffer[offset + 0] = (byte) BC_DOUBLE_SHORT;
+ buffer[offset + 1] = (byte) (intValue >> 8);
+ buffer[offset + 2] = (byte) intValue;
+
+ _offset = offset + 3;
+
+ return;
+ }
+ }
+
+ int mills = (int) (value * 1000);
+
+ if (0.001 * mills == value) {
+ buffer[offset + 0] = (byte) (BC_DOUBLE_MILL);
+ buffer[offset + 1] = (byte) (mills >> 24);
+ buffer[offset + 2] = (byte) (mills >> 16);
+ buffer[offset + 3] = (byte) (mills >> 8);
+ buffer[offset + 4] = (byte) (mills);
+
+ _offset = offset + 5;
+
+ return;
+ }
+
+ long bits = Double.doubleToLongBits(value);
+
+ buffer[offset + 0] = (byte) 'D';
+ buffer[offset + 1] = (byte) (bits >> 56);
+ buffer[offset + 2] = (byte) (bits >> 48);
+ buffer[offset + 3] = (byte) (bits >> 40);
+ buffer[offset + 4] = (byte) (bits >> 32);
+ buffer[offset + 5] = (byte) (bits >> 24);
+ buffer[offset + 6] = (byte) (bits >> 16);
+ buffer[offset + 7] = (byte) (bits >> 8);
+ buffer[offset + 8] = (byte) (bits);
+
+ _offset = offset + 9;
+ }
+
+ /**
+ * Writes a date to the stream.
+ * <p>
+ * <code><pre>
+ * date ::= d b7 b6 b5 b4 b3 b2 b1 b0
+ * ::= x65 b3 b2 b1 b0
+ * </pre></code>
+ *
+ * @param time the date in milliseconds from the epoch in UTC
+ */
+ @Override
+ public void writeUTCDate(long time)
+ throws IOException {
+ if (SIZE < _offset + 32)
+ flush();
+
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ if (time % 60000L == 0) {
+ // compact date ::= x65 b3 b2 b1 b0
+
+ long minutes = time / 60000L;
+
+ if ((minutes >> 31) == 0 || (minutes >> 31) == -1) {
+ buffer[offset++] = (byte) BC_DATE_MINUTE;
+ buffer[offset++] = ((byte) (minutes >> 24));
+ buffer[offset++] = ((byte) (minutes >> 16));
+ buffer[offset++] = ((byte) (minutes >> 8));
+ buffer[offset++] = ((byte) (minutes >> 0));
+
+ _offset = offset;
+ return;
+ }
+ }
+
+ buffer[offset++] = (byte) BC_DATE;
+ buffer[offset++] = ((byte) (time >> 56));
+ buffer[offset++] = ((byte) (time >> 48));
+ buffer[offset++] = ((byte) (time >> 40));
+ buffer[offset++] = ((byte) (time >> 32));
+ buffer[offset++] = ((byte) (time >> 24));
+ buffer[offset++] = ((byte) (time >> 16));
+ buffer[offset++] = ((byte) (time >> 8));
+ buffer[offset++] = ((byte) (time));
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a null value to the stream.
+ * The null will be written with the following syntax
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ @Override
+ public void writeNull()
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ buffer[offset++] = 'N';
+
+ _offset = offset;
+ }
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * S b16 b8 string-value
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ @Override
+ public void writeString(String value)
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (value == null) {
+ buffer[offset++] = (byte) 'N';
+
+ _offset = offset;
+ } else {
+ int length = value.length();
+ int strOffset = 0;
+
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ offset = _offset;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ // chunk can't end in high surrogate
+ char tail = value.charAt(strOffset + sublen - 1);
+
+ if (0xd800 <= tail && tail <= 0xdbff)
+ sublen--;
+
+ buffer[offset + 0] = (byte) BC_STRING_CHUNK;
+ buffer[offset + 1] = (byte) (sublen >> 8);
+ buffer[offset + 2] = (byte) (sublen);
+
+ _offset = offset + 3;
+
+ printString(value, strOffset, sublen);
+
+ length -= sublen;
+ strOffset += sublen;
+ }
+
+ offset = _offset;
+
+ if (SIZE <= offset + 16) {
+ flush();
+ offset = _offset;
+ }
+
+ if (length <= STRING_DIRECT_MAX) {
+ buffer[offset++] = (byte) (BC_STRING_DIRECT + length);
+ } else if (length <= STRING_SHORT_MAX) {
+ buffer[offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
+ buffer[offset++] = (byte) (length);
+ } else {
+ buffer[offset++] = (byte) ('S');
+ buffer[offset++] = (byte) (length >> 8);
+ buffer[offset++] = (byte) (length);
+ }
+
+ _offset = offset;
+
+ printString(value, strOffset, length);
+ }
+ }
+
+ /**
+ * Writes a string value to the stream using UTF-8 encoding.
+ * The string will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * S b16 b8 string-value
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ @Override
+ public void writeString(char[] buffer, int offset, int length)
+ throws IOException {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flush();
+
+ _buffer[_offset++] = (byte) ('N');
+ } else {
+ while (length > 0x8000) {
+ int sublen = 0x8000;
+
+ if (SIZE < _offset + 16)
+ flush();
+
+ // chunk can't end in high surrogate
+ char tail = buffer[offset + sublen - 1];
+
+ if (0xd800 <= tail && tail <= 0xdbff)
+ sublen--;
+
+ _buffer[_offset++] = (byte) BC_STRING_CHUNK;
+ _buffer[_offset++] = (byte) (sublen >> 8);
+ _buffer[_offset++] = (byte) (sublen);
+
+ printString(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+
+ if (SIZE < _offset + 16)
+ flush();
+
+ if (length <= STRING_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_STRING_DIRECT + length);
+ } else if (length <= STRING_SHORT_MAX) {
+ _buffer[_offset++] = (byte) (BC_STRING_SHORT + (length >> 8));
+ _buffer[_offset++] = (byte) length;
+ } else {
+ _buffer[_offset++] = (byte) ('S');
+ _buffer[_offset++] = (byte) (length >> 8);
+ _buffer[_offset++] = (byte) (length);
+ }
+
+ printString(buffer, offset, length);
+ }
+ }
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * B b16 b18 bytes
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ @Override
+ public void writeBytes(byte[] buffer)
+ throws IOException {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flush();
+
+ _buffer[_offset++] = 'N';
+ } else
+ writeBytes(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Writes a byte array to the stream.
+ * The array will be written with the following syntax:
+ * <p>
+ * <code><pre>
+ * B b16 b18 bytes
+ * </pre></code>
+ * <p>
+ * If the value is null, it will be written as
+ * <p>
+ * <code><pre>
+ * N
+ * </pre></code>
+ *
+ * @param value the string value to write.
+ */
+ @Override
+ public void writeBytes(byte[] buffer, int offset, int length)
+ throws IOException {
+ if (buffer == null) {
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ _buffer[_offset++] = (byte) 'N';
+ } else {
+ flush();
+
+ while (SIZE - _offset - 3 < length) {
+ int sublen = SIZE - _offset - 3;
+
+ if (sublen < 16) {
+ flushBuffer();
+
+ sublen = SIZE - _offset - 3;
+
+ if (length < sublen)
+ sublen = length;
+ }
+
+ _buffer[_offset++] = (byte) BC_BINARY_CHUNK;
+ _buffer[_offset++] = (byte) (sublen >> 8);
+ _buffer[_offset++] = (byte) sublen;
+
+ System.arraycopy(buffer, offset, _buffer, _offset, sublen);
+ _offset += sublen;
+
+ length -= sublen;
+ offset += sublen;
+
+ flushBuffer();
+ }
+
+ if (SIZE < _offset + 16)
+ flushBuffer();
+
+ if (length <= BINARY_DIRECT_MAX) {
+ _buffer[_offset++] = (byte) (BC_BINARY_DIRECT + length);
+ } else if (length <= BINARY_SHORT_MAX) {
+ _buffer[_offset++] = (byte) (BC_BINARY_SHORT + (length >> 8));
+ _buffer[_offset++] = (byte) (length);
+ } else {
+ _buffer[_offset++] = (byte) 'B';
+ _buffer[_offset++] = (byte) (length >> 8);
+ _buffer[_offset++] = (byte) (length);
+ }
+
+ System.arraycopy(buffer, offset, _buffer, _offset, length);
+
+ _offset += length;
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ * <p>
+ * <code><pre>
+ * </pre></code>
+ */
+ @Override
+ public void writeByteBufferStart()
+ throws IOException {
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ * <p>
+ * <code><pre>
+ * b b16 b18 bytes
+ * </pre></code>
+ */
+ @Override
+ public void writeByteBufferPart(byte[] buffer, int offset, int length)
+ throws IOException {
+ while (length > 0) {
+ int sublen = length;
+
+ if (0x8000 < sublen)
+ sublen = 0x8000;
+
+ flush(); // bypass buffer
+
+ _os.write(BC_BINARY_CHUNK);
+ _os.write(sublen >> 8);
+ _os.write(sublen);
+
+ _os.write(buffer, offset, sublen);
+
+ length -= sublen;
+ offset += sublen;
+ }
+ }
+
+ /**
+ * Writes a byte buffer to the stream.
+ * <p>
+ * <code><pre>
+ * b b16 b18 bytes
+ * </pre></code>
+ */
+ @Override
+ public void writeByteBufferEnd(byte[] buffer, int offset, int length)
+ throws IOException {
+ writeBytes(buffer, offset, length);
+ }
+
+ /**
+ * Returns an output stream to write binary data.
+ */
+ public OutputStream getBytesOutputStream()
+ throws IOException {
+ return new BytesOutputStream();
+ }
+
+ /**
+ * Writes a reference.
+ * <p>
+ * <code><pre>
+ * x51 <int>
+ * </pre></code>
+ *
+ * @param value the integer value to write.
+ */
+ @Override
+ protected void writeRef(int value)
+ throws IOException {
+ if (SIZE < _offset + 16)
+ flush();
+
+ _buffer[_offset++] = (byte) BC_REF;
+
+ writeInt(value);
+ }
+
+ /**
+ * If the object has already been written, just write its ref.
+ *
+ * @return true if we're writing a ref.
+ */
+ @Override
+ public boolean addRef(Object object)
+ throws IOException {
+ int ref = _refs.get(object);
+
+ if (ref >= 0) {
+ writeRef(ref);
+
+ return true;
+ } else {
+ _refs.put(object, _refs.size());
+
+ return false;
+ }
+ }
+
+ /**
+ * Removes a reference.
+ */
+ @Override
+ public boolean removeRef(Object obj)
+ throws IOException {
+ if (_refs != null) {
+ _refs.remove(obj);
+
+ return true;
+ } else
+ return false;
+ }
+
+ /**
+ * Replaces a reference from one object to another.
+ */
+ @Override
+ public boolean replaceRef(Object oldRef, Object newRef)
+ throws IOException {
+ Integer value = (Integer) _refs.remove(oldRef);
+
+ if (value != null) {
+ _refs.put(newRef, value);
+ return true;
+ } else
+ return false;
+ }
+
+ /**
+ * Resets the references for streaming.
+ */
+ @Override
+ public void resetReferences() {
+ if (_refs != null)
+ _refs.clear();
+ }
+
+ /**
+ * Starts the streaming message
+ * <p>
+ * <p>A streaming message starts with 'P'</p>
+ * <p>
+ * <pre>
+ * P x02 x00
+ * </pre>
+ */
+ public void writeStreamingObject(Object obj)
+ throws IOException {
+ startStreamingPacket();
+
+ writeObject(obj);
+
+ endStreamingPacket();
+ }
+
+ /**
+ * Starts a streaming packet
+ * <p>
+ * <p>A streaming message starts with 'P'</p>
+ * <p>
+ * <pre>
+ * P x02 x00
+ * </pre>
+ */
+ public void startStreamingPacket()
+ throws IOException {
+ if (_refs != null)
+ _refs.clear();
+
+ flush();
+
+ _isStreaming = true;
+ _offset = 3;
+ }
+
+ public void endStreamingPacket()
+ throws IOException {
+ int len = _offset - 3;
+
+ _buffer[0] = (byte) 'P';
+ _buffer[1] = (byte) (len >> 8);
+ _buffer[2] = (byte) len;
+
+ _isStreaming = false;
+
+ flush();
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8 with preceeding length
+ *
+ * @param v the string to print.
+ */
+ public void printLenString(String v)
+ throws IOException {
+ if (SIZE < _offset + 16)
+ flush();
+
+ if (v == null) {
+ _buffer[_offset++] = (byte) (0);
+ _buffer[_offset++] = (byte) (0);
+ } else {
+ int len = v.length();
+ _buffer[_offset++] = (byte) (len >> 8);
+ _buffer[_offset++] = (byte) (len);
+
+ printString(v, 0, len);
+ }
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8
+ *
+ * @param v the string to print.
+ */
+ public void printString(String v)
+ throws IOException {
+ printString(v, 0, v.length());
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8
+ *
+ * @param v the string to print.
+ */
+ public void printString(String v, int strOffset, int length)
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ for (int i = 0; i < length; i++) {
+ if (SIZE <= offset + 16) {
+ _offset = offset;
+ flush();
+ offset = _offset;
+ }
+
+ char ch = v.charAt(i + strOffset);
+
+ if (ch < 0x80)
+ buffer[offset++] = (byte) (ch);
+ else if (ch < 0x800) {
+ buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
+ buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
+ } else {
+ buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
+ buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
+ buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
+ }
+ }
+
+ _offset = offset;
+ }
+
+ /**
+ * Prints a string to the stream, encoded as UTF-8
+ *
+ * @param v the string to print.
+ */
+ public void printString(char[] v, int strOffset, int length)
+ throws IOException {
+ int offset = _offset;
+ byte[] buffer = _buffer;
+
+ for (int i = 0; i < length; i++) {
+ if (SIZE <= offset + 16) {
+ _offset = offset;
+ flush();
+ offset = _offset;
+ }
+
+ char ch = v[i + strOffset];
+
+ if (ch < 0x80)
+ buffer[offset++] = (byte) (ch);
+ else if (ch < 0x800) {
+ buffer[offset++] = (byte) (0xc0 + ((ch >> 6) & 0x1f));
+ buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
+ } else {
+ buffer[offset++] = (byte) (0xe0 + ((ch >> 12) & 0xf));
+ buffer[offset++] = (byte) (0x80 + ((ch >> 6) & 0x3f));
+ buffer[offset++] = (byte) (0x80 + (ch & 0x3f));
+ }
+ }
+
+ _offset = offset;
+ }
+
+ private final void flushIfFull()
+ throws IOException {
+ int offset = _offset;
+
+ if (SIZE < offset + 32) {
+ _offset = 0;
+ _os.write(_buffer, 0, offset);
+ }
+ }
+
+ @Override
+ public final void flush()
+ throws IOException {
+ flushBuffer();
+
+ if (_os != null)
+ _os.flush();
+ }
+
+ public final void flushBuffer()
+ throws IOException {
+ int offset = _offset;
+
+ if (!_isStreaming && offset > 0) {
+ _offset = 0;
+
+ _os.write(_buffer, 0, offset);
+ } else if (_isStreaming && offset > 3) {
+ int len = offset - 3;
+ _buffer[0] = 'p';
+ _buffer[1] = (byte) (len >> 8);
+ _buffer[2] = (byte) len;
+ _offset = 3;
+
+ _os.write(_buffer, 0, offset);
+ }
+ }
+
+ @Override
+ public final void close()
+ throws IOException {
+ // hessian/3a8c
+ flush();
+
+ OutputStream os = _os;
+ _os = null;
+
+ if (os != null) {
+ if (_isCloseStreamOnClose)
+ os.close();
+ }
+ }
+
+ class BytesOutputStream extends OutputStream {
+ private int _startOffset;
+
+ BytesOutputStream()
+ throws IOException {
+ if (SIZE < _offset + 16) {
+ Hessian2Output.this.flush();
+ }
+
+ _startOffset = _offset;
+ _offset += 3; // skip 'b' xNN xNN
+ }
+
+ @Override
+ public void write(int ch)
+ throws IOException {
+ if (SIZE <= _offset) {
+ int length = (_offset - _startOffset) - 3;
+
+ _buffer[_startOffset] = (byte) BC_BINARY_CHUNK;
+ _buffer[_startOffset + 1] = (byte) (length >> 8);
+ _buffer[_startOffset + 2] = (byte) (length);
+
+ Hessian2Output.this.flush();
+
+ _startOffset = _offset;
+ _offset += 3;
+ }
+
+ _buffer[_offset++] = (byte) ch;
+ }
+
+ @Override
+ public void write(byte[] buffer, int offset, int length)
+ throws IOException {
+ while (length > 0) {
+ int sublen = SIZE - _offset;
+
+ if (length < sublen)
+ sublen = length;
+
+ if (sublen > 0) {
+ System.arraycopy(buffer, offset, _buffer, _offset, sublen);
+ _offset += sublen;
+ }
+
+ length -= sublen;
+ offset += sublen;
+
+ if (SIZE <= _offset) {
+ int chunkLength = (_offset - _startOffset) - 3;
+
+ _buffer[_startOffset] = (byte) BC_BINARY_CHUNK;
+ _buffer[_startOffset + 1] = (byte) (chunkLength >> 8);
+ _buffer[_startOffset + 2] = (byte) (chunkLength);
+
+ Hessian2Output.this.flush();
+
+ _startOffset = _offset;
+ _offset += 3;
+ }
+ }
+ }
+
+ @Override
+ public void close()
+ throws IOException {
+ int startOffset = _startOffset;
+ _startOffset = -1;
+
+ if (startOffset < 0)
+ return;
+
+ int length = (_offset - startOffset) - 3;
+
+ _buffer[startOffset] = (byte) 'B';
+ _buffer[startOffset + 1] = (byte) (length >> 8);
+ _buffer[startOffset + 2] = (byte) (length);
+
+ Hessian2Output.this.flush();
+ }
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2StreamingInput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2StreamingInput.java
new file mode 100644
index 0000000..35316cc
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2StreamingInput.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Output stream for Hessian 2 streaming requests.
+ */
+public class Hessian2StreamingInput {
+ private Hessian2Input _in;
+
+ /**
+ * Creates a new Hessian input stream, initialized with an
+ * underlying input stream.
+ *
+ * @param is the underlying output stream.
+ */
+ public Hessian2StreamingInput(InputStream is) {
+ _in = new Hessian2Input(new StreamingInputStream(is));
+ }
+
+ /**
+ * Read the next object
+ */
+ public Object readObject()
+ throws IOException {
+ return _in.readStreamingObject();
+ }
+
+ /**
+ * Close the output.
+ */
+ public void close()
+ throws IOException {
+ _in.close();
+ }
+
+ static class StreamingInputStream extends InputStream {
+ private InputStream _is;
+ private int _length;
+
+ StreamingInputStream(InputStream is) {
+ _is = is;
+ }
+
+ @Override
+ public int read()
+ throws IOException {
+ InputStream is = _is;
+
+ while (_length == 0) {
+ int code = is.read();
+
+ if (code < 0)
+ return -1;
+ else if (code != 'p' && code != 'P')
+ throw new HessianProtocolException("expected streaming packet at 0x"
+ + Integer.toHexString(code & 0xff));
+
+ int d1 = is.read();
+ int d2 = is.read();
+
+ if (d2 < 0)
+ return -1;
+
+ _length = (d1 << 8) + d2;
+ }
+
+ _length--;
+ return is.read();
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int length)
+ throws IOException {
+ InputStream is = _is;
+
+ while (_length == 0) {
+ int code = is.read();
+
+ if (code < 0)
+ return -1;
+ else if (code != 'p' && code != 'P') {
+ throw new HessianProtocolException("expected streaming packet at 0x"
+ + Integer.toHexString(code & 0xff)
+ + " (" + (char) code + ")");
+ }
+
+ int d1 = is.read();
+ int d2 = is.read();
+
+ if (d2 < 0)
+ return -1;
+
+ _length = (d1 << 8) + d2;
+ }
+
+ int sublen = _length;
+ if (length < sublen)
+ sublen = length;
+
+ sublen = is.read(buffer, offset, sublen);
+
+ if (sublen < 0)
+ return -1;
+
+ _length -= sublen;
+
+ return sublen;
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2StreamingOutput.java
similarity index 65%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2StreamingOutput.java
index 7c8e328..a2edf24 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Hessian2StreamingOutput.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,35 +46,56 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
/**
- * Factory for returning serialization methods.
+ * Output stream for Hessian 2 streaming requests.
*/
-public class BeanSerializerFactory extends SerializerFactory {
+public class Hessian2StreamingOutput {
+ private Hessian2Output _out;
+
/**
- * Returns the default serializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
+ * Creates a new Hessian output stream, initialized with an
+ * underlying output stream.
*
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
+ * @param os the underlying output stream.
*/
- @Override
- protected Serializer getDefaultSerializer(Class cl) {
- return new BeanSerializer(cl, getClassLoader());
+ public Hessian2StreamingOutput(OutputStream os) {
+ _out = new Hessian2Output(os);
+ }
+
+ public boolean isCloseStreamOnClose() {
+ return _out.isCloseStreamOnClose();
+ }
+
+ public void setCloseStreamOnClose(boolean isClose) {
+ _out.setCloseStreamOnClose(isClose);
}
/**
- * Returns the default deserializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
+ * Writes any object to the output stream.
*/
- @Override
- protected Deserializer getDefaultDeserializer(Class cl) {
- return new BeanDeserializer(cl);
+ public void writeObject(Object object)
+ throws IOException {
+ _out.writeStreamingObject(object);
+ }
+
+ /**
+ * Flushes the output.
+ */
+ public void flush()
+ throws IOException {
+ _out.flush();
+ }
+
+ /**
+ * Close the output.
+ */
+ public void close()
+ throws IOException {
+ _out.close();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugInputStream.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugInputStream.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugInputStream.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugInputStream.java
index 092fa22..2cdc1b0 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugInputStream.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugInputStream.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugOutputStream.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugOutputStream.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugOutputStream.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugOutputStream.java
index 5d45d93..0d145f4 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugOutputStream.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugOutputStream.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.OutputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugState.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugState.java
similarity index 99%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugState.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugState.java
index 0798289..7c4f7b5 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianDebugState.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianDebugState.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.PrintWriter;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianEnvelope.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianEnvelope.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianEnvelope.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianEnvelope.java
index 21bd3a7..1e4e6de 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianEnvelope.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianEnvelope.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianFieldException.java
similarity index 75%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianFieldException.java
index 72a9822..7f8309e 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianFieldException.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,36 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
-
-import java.io.IOException;
+package com.alibaba.com.caucho.hessian3.io;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Exception during field reading.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class HessianFieldException extends HessianProtocolException {
/**
- * Looks up a proxy object.
+ * Zero-arg constructor.
*/
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public HessianFieldException() {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianFieldException(String message) {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianFieldException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianFieldException(Throwable cause) {
+ super(cause);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianHandle.java
similarity index 90%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianHandle.java
index be505fb..ac447d2 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianHandle.java
@@ -46,11 +46,10 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
-import java.util.logging.Logger;
-
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Marks a type as a handle
+ */
+public interface HessianHandle {
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianInput.java
similarity index 99%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianInput.java
index 14b3096..8d0ebd8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInput.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianInput.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInputFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianInputFactory.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianInputFactory.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianInputFactory.java
index 2c0cf69..02b2580 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianInputFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianInputFactory.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianOutput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianOutput.java
similarity index 99%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianOutput.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianOutput.java
index aad614b..c07ace9 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianOutput.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianOutput.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.OutputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianProtocolException.java
similarity index 65%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianProtocolException.java
index 7c8e328..16d98d3 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianProtocolException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,35 +46,60 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
/**
- * Factory for returning serialization methods.
+ * Exception for faults when the fault doesn't return a java exception.
+ * This exception is required for MicroHessianInput.
*/
-public class BeanSerializerFactory extends SerializerFactory {
+public class HessianProtocolException extends IOException {
+ private Throwable rootCause;
+
/**
- * Returns the default serializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
+ * Zero-arg constructor.
*/
- @Override
- protected Serializer getDefaultSerializer(Class cl) {
- return new BeanSerializer(cl, getClassLoader());
+ public HessianProtocolException() {
}
/**
- * Returns the default deserializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
+ * Create the exception.
+ */
+ public HessianProtocolException(String message) {
+ super(message);
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianProtocolException(String message, Throwable rootCause) {
+ super(message);
+
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianProtocolException(Throwable rootCause) {
+ super(String.valueOf(rootCause));
+
+ this.rootCause = rootCause;
+ }
+
+ /**
+ * Returns the underlying cause.
+ */
+ public Throwable getRootCause() {
+ return rootCause;
+ }
+
+ /**
+ * Returns the underlying cause.
*/
@Override
- protected Deserializer getDefaultDeserializer(Class cl) {
- return new BeanDeserializer(cl);
+ public Throwable getCause() {
+ return getRootCause();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemote.java
similarity index 61%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemote.java
index 72a9822..d43527d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemote.java
@@ -46,20 +46,80 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
-
-import java.io.IOException;
+package com.alibaba.com.caucho.hessian3.io;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Encapsulates a remote address when no stub is available, e.g. for
+ * Java MicroEdition.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class HessianRemote {
+ private String type;
+ private String url;
+
/**
- * Looks up a proxy object.
+ * Creates a new Hessian remote object.
+ *
+ * @param type the remote stub interface
+ * @param url the remote url
+ */
+ public HessianRemote(String type, String url) {
+ this.type = type;
+ this.url = url;
+ }
+
+ /**
+ * Creates an uninitialized Hessian remote.
+ */
+ public HessianRemote() {
+ }
+
+ /**
+ * Returns the remote api class name.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Returns the remote URL.
+ */
+ public String getURL() {
+ return url;
+ }
+
+ /**
+ * Sets the remote URL.
+ */
+ public void setURL(String url) {
+ this.url = url;
+ }
+
+ /**
+ * Defines the hashcode.
*/
@Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public int hashCode() {
+ return url.hashCode();
+ }
+
+ /**
+ * Defines equality
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof HessianRemote))
+ return false;
+
+ HessianRemote remote = (HessianRemote) obj;
+
+ return url.equals(remote.url);
+ }
+
+ /**
+ * Readable version of the remote.
+ */
+ @Override
+ public String toString() {
+ return "[HessianRemote " + url + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemoteObject.java
similarity index 90%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemoteObject.java
index be505fb..a36e583 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemoteObject.java
@@ -46,11 +46,13 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
-import java.util.logging.Logger;
+/**
+ * Interface for any hessian remote object.
+ */
+public interface HessianRemoteObject {
+ public String getHessianType();
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+ public String getHessianURL();
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemoteResolver.java
similarity index 91%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemoteResolver.java
index 72a9822..0e2b947 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianRemoteResolver.java
@@ -46,20 +46,17 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
* Looks up remote objects. The default just returns a HessianRemote object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public interface HessianRemoteResolver {
/**
* Looks up a proxy object.
*/
- @Override
public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
- }
+ throws IOException;
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerInput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianSerializerInput.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerInput.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianSerializerInput.java
index ceed54b..e87904f 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerInput.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianSerializerInput.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerOutput.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianSerializerOutput.java
similarity index 98%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerOutput.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianSerializerOutput.java
index 56a8772..f359807 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/HessianSerializerOutput.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianSerializerOutput.java
@@ -46,7 +46,7 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.io.OutputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianServiceException.java
similarity index 74%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/HessianServiceException.java
index 72a9822..b2ccc1b 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/HessianServiceException.java
@@ -46,20 +46,42 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
-
-import java.io.IOException;
+package com.alibaba.com.caucho.hessian3.io;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Exception for faults when the fault doesn't return a java exception.
+ * This exception is required for MicroHessianInput.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class HessianServiceException extends Exception {
+ private String code;
+ private Object detail;
+
/**
- * Looks up a proxy object.
+ * Zero-arg constructor.
*/
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public HessianServiceException() {
+ }
+
+ /**
+ * Create the exception.
+ */
+ public HessianServiceException(String message, String code, Object detail) {
+ super(message);
+ this.code = code;
+ this.detail = detail;
+ }
+
+ /**
+ * Returns the code.
+ */
+ public String getCode() {
+ return code;
+ }
+
+ /**
+ * Returns the detail.
+ */
+ public Object getDetail() {
+ return detail;
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/IOExceptionWrapper.java
similarity index 83%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/IOExceptionWrapper.java
index 72a9822..c35cbc1 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/IOExceptionWrapper.java
@@ -46,20 +46,30 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Exception wrapper for IO.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class IOExceptionWrapper extends IOException {
+ private Throwable _cause;
+
+ public IOExceptionWrapper(Throwable cause) {
+ super(cause.toString());
+
+ _cause = cause;
+ }
+
+ public IOExceptionWrapper(String msg, Throwable cause) {
+ super(msg);
+
+ _cause = cause;
+ }
+
@Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ public Throwable getCause() {
+ return _cause;
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/InputStreamDeserializer.java
similarity index 84%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/InputStreamDeserializer.java
index 72a9822..d659dac 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/InputStreamDeserializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,20 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a stream object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class InputStreamDeserializer extends AbstractDeserializer {
+ public InputStreamDeserializer() {
+ }
+
@Override
- public Object lookup(String type, String url)
+ public Object readObject(AbstractHessianInput in)
throws IOException {
- return new HessianRemote(type, url);
+ return in.readInputStream();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/InputStreamSerializer.java
similarity index 75%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/InputStreamSerializer.java
index 72a9822..bbc036d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/InputStreamSerializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,34 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.io.InputStream;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a stream object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class InputStreamSerializer extends AbstractSerializer {
+ public InputStreamSerializer() {
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ InputStream is = (InputStream) obj;
+
+ if (is == null)
+ out.writeNull();
+ else {
+ byte[] buf = new byte[1024];
+ int len;
+
+ while ((len = is.read(buf, 0, buf.length)) > 0) {
+ out.writeByteBufferPart(buf, 0, len);
+ }
+
+ out.writeByteBufferEnd(buf, 0, 0);
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/IteratorSerializer.java
similarity index 75%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/IteratorSerializer.java
index 72a9822..ed729fb 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/IteratorSerializer.java
@@ -46,20 +46,38 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.Iterator;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a JDK 1.2 Iterator.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class IteratorSerializer extends AbstractSerializer {
+ private static IteratorSerializer _serializer;
+
+ public static IteratorSerializer create() {
+ if (_serializer == null)
+ _serializer = new IteratorSerializer();
+
+ return _serializer;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ Iterator iter = (Iterator) obj;
+
+ boolean hasEnd = out.writeListBegin(-1, null);
+
+ while (iter.hasNext()) {
+ Object value = iter.next();
+
+ out.writeObject(value);
+ }
+
+ if (hasEnd)
+ out.writeListEnd();
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/JavaDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/JavaDeserializer.java
new file mode 100644
index 0000000..f24debf
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/JavaDeserializer.java
@@ -0,0 +1,786 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class JavaDeserializer extends AbstractMapDeserializer {
+ private static final Logger log
+ = Logger.getLogger(JavaDeserializer.class.getName());
+
+ private Class _type;
+ private HashMap _fieldMap;
+ private Method _readResolve;
+ private Constructor _constructor;
+ private Object[] _constructorArgs;
+
+ public JavaDeserializer(Class cl) {
+ _type = cl;
+ _fieldMap = getFieldMap(cl);
+
+ _readResolve = getReadResolve(cl);
+
+ if (_readResolve != null) {
+ _readResolve.setAccessible(true);
+ }
+
+ Constructor[] constructors = cl.getDeclaredConstructors();
+ long bestCost = Long.MAX_VALUE;
+
+ for (int i = 0; i < constructors.length; i++) {
+ Class[] param = constructors[i].getParameterTypes();
+ long cost = 0;
+
+ for (int j = 0; j < param.length; j++) {
+ cost = 4 * cost;
+
+ if (Object.class.equals(param[j]))
+ cost += 1;
+ else if (String.class.equals(param[j]))
+ cost += 2;
+ else if (int.class.equals(param[j]))
+ cost += 3;
+ else if (long.class.equals(param[j]))
+ cost += 4;
+ else if (param[j].isPrimitive())
+ cost += 5;
+ else
+ cost += 6;
+ }
+
+ if (cost < 0 || cost > (1 << 48))
+ cost = 1 << 48;
+
+ cost += (long) param.length << 48;
+
+ if (cost < bestCost) {
+ _constructor = constructors[i];
+ bestCost = cost;
+ }
+ }
+
+ if (_constructor != null) {
+ _constructor.setAccessible(true);
+ Class[] params = _constructor.getParameterTypes();
+ _constructorArgs = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ _constructorArgs[i] = getParamArg(params[i]);
+ }
+ }
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected static Object getParamArg(Class cl) {
+ if (!cl.isPrimitive())
+ return null;
+ else if (boolean.class.equals(cl))
+ return Boolean.FALSE;
+ else if (byte.class.equals(cl))
+ return new Byte((byte) 0);
+ else if (short.class.equals(cl))
+ return new Short((short) 0);
+ else if (char.class.equals(cl))
+ return new Character((char) 0);
+ else if (int.class.equals(cl))
+ return Integer.valueOf(0);
+ else if (long.class.equals(cl))
+ return Long.valueOf(0);
+ else if (float.class.equals(cl))
+ return Float.valueOf(0);
+ else if (double.class.equals(cl))
+ return Double.valueOf(0);
+ else
+ throw new UnsupportedOperationException();
+ }
+
+ static void logDeserializeError(Field field, Object obj, Object value,
+ Throwable e)
+ throws IOException {
+ String fieldName = (field.getDeclaringClass().getName()
+ + "." + field.getName());
+
+ if (e instanceof HessianFieldException)
+ throw (HessianFieldException) e;
+ else if (e instanceof IOException)
+ throw new HessianFieldException(fieldName + ": " + e.getMessage(), e);
+
+ if (value != null)
+ throw new HessianFieldException(fieldName + ": " + value.getClass().getName()
+ + " cannot be assigned to '" + field.getType().getName() + "'", e);
+ else
+ throw new HessianFieldException(fieldName + ": " + field.getType().getName() + " cannot be assigned from null", e);
+ }
+
+ @Override
+ public Class getType() {
+ return _type;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readMap(in, obj);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ try {
+ Object obj = instantiate();
+
+ return readObject(in, obj, fieldNames);
+ } catch (IOException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(_type.getName() + ":" + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Returns the readResolve method
+ */
+ protected Method getReadResolve(Class cl) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("readResolve") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ public Object readMap(AbstractHessianInput in, Object obj)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ while (!in.isEnd()) {
+ Object key = in.readObject();
+
+ FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(key);
+
+ if (deser != null)
+ deser.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object resolve = resolve(obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ public Object readObject(AbstractHessianInput in,
+ Object obj,
+ String[] fieldNames)
+ throws IOException {
+ try {
+ int ref = in.addRef(obj);
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String name = fieldNames[i];
+
+ FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(name);
+
+ if (deser != null)
+ deser.deserialize(in, obj);
+ else
+ in.readObject();
+ }
+
+ Object resolve = resolve(obj);
+
+ if (obj != resolve)
+ in.setRef(ref, resolve);
+
+ return resolve;
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e);
+ }
+ }
+
+ private Object resolve(Object obj)
+ throws Exception {
+ // if there's a readResolve method, call it
+ try {
+ if (_readResolve != null)
+ return _readResolve.invoke(obj, new Object[0]);
+ } catch (InvocationTargetException e) {
+ if (e.getTargetException() != null)
+ throw e;
+ }
+
+ return obj;
+ }
+
+ protected Object instantiate()
+ throws Exception {
+ try {
+ if (_constructor != null)
+ return _constructor.newInstance(_constructorArgs);
+ else
+ return _type.newInstance();
+ } catch (Exception e) {
+ throw new HessianProtocolException("'" + _type.getName() + "' could not be instantiated", e);
+ }
+ }
+
+ /**
+ * Creates a map of the classes fields.
+ */
+ protected HashMap getFieldMap(Class cl) {
+ HashMap fieldMap = new HashMap();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field[] fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers()))
+ continue;
+ else if (fieldMap.get(field.getName()) != null)
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ try {
+ field.setAccessible(true);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ Class type = field.getType();
+ FieldDeserializer deser;
+
+ if (String.class.equals(type))
+ deser = new StringFieldDeserializer(field);
+ else if (byte.class.equals(type)) {
+ deser = new ByteFieldDeserializer(field);
+ } else if (short.class.equals(type)) {
+ deser = new ShortFieldDeserializer(field);
+ } else if (int.class.equals(type)) {
+ deser = new IntFieldDeserializer(field);
+ } else if (long.class.equals(type)) {
+ deser = new LongFieldDeserializer(field);
+ } else if (float.class.equals(type)) {
+ deser = new FloatFieldDeserializer(field);
+ } else if (double.class.equals(type)) {
+ deser = new DoubleFieldDeserializer(field);
+ } else if (boolean.class.equals(type)) {
+ deser = new BooleanFieldDeserializer(field);
+ } else if (java.sql.Date.class.equals(type)) {
+ deser = new SqlDateFieldDeserializer(field);
+ } else if (java.sql.Timestamp.class.equals(type)) {
+ deser = new SqlTimestampFieldDeserializer(field);
+ } else if (java.sql.Time.class.equals(type)) {
+ deser = new SqlTimeFieldDeserializer(field);
+ }
+ // support generic type of map
+ else if (Map.class.equals(type)
+ && field.getGenericType() != field.getType()) {
+ deser = new ObjectMapFieldDeserializer(field);
+ } else if (List.class.equals(type)
+ && field.getGenericType() != field.getType()) {
+ deser = new ObjectListFieldDeserializer(field);
+ } else if (Set.class.equals(type)
+ && field.getGenericType() != field.getType()) {
+ deser = new ObjectSetFieldDeserializer(field);
+ }
+ else {
+ deser = new ObjectFieldDeserializer(field);
+ }
+
+ fieldMap.put(field.getName(), deser);
+ }
+ }
+
+ return fieldMap;
+ }
+
+ abstract static class FieldDeserializer {
+ abstract void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException;
+ }
+
+ static class ObjectFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ObjectFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ Object value = null;
+
+ try {
+ value = in.readObject(_field.getType());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class BooleanFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ BooleanFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ boolean value = false;
+
+ try {
+ value = in.readBoolean();
+
+ _field.setBoolean(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ByteFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ByteFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setByte(obj, (byte) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ShortFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ShortFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setShort(obj, (short) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ObjectMapFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ObjectMapFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ Object value = null;
+
+ try {
+
+ Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
+ value = in.readObject(_field.getType(),
+ isPrimitive(types[0]) ? (Class<?>) types[0] : null,
+ isPrimitive(types[1]) ? (Class<?>) types[1] : null
+ );
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ObjectListFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ObjectListFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ Object value = null;
+
+ try {
+
+ Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
+ value = in.readObject(_field.getType(),
+ isPrimitive(types[0]) ? (Class<?>) types[0] : null
+ );
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class ObjectSetFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ ObjectSetFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ Object value = null;
+
+ try {
+
+ Type[] types = ((ParameterizedType) _field.getGenericType()).getActualTypeArguments();
+ value = in.readObject(_field.getType(),
+ isPrimitive(types[0]) ? (Class<?>) types[0] : null
+ );
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+
+ static class IntFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ IntFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = in.readInt();
+
+ _field.setInt(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class LongFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ LongFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ long value = 0;
+
+ try {
+ value = in.readLong();
+
+ _field.setLong(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class FloatFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ FloatFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _field.setFloat(obj, (float) value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class DoubleFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ DoubleFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = in.readDouble();
+
+ _field.setDouble(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class StringFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ StringFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ String value = null;
+
+ try {
+ value = in.readString();
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlDateFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ SqlDateFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Date value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+ if (date != null)
+ value = new java.sql.Date(date.getTime());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimestampFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ SqlTimestampFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Timestamp value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+ if (date != null)
+ value = new java.sql.Timestamp(date.getTime());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ static class SqlTimeFieldDeserializer extends FieldDeserializer {
+ private final Field _field;
+
+ SqlTimeFieldDeserializer(Field field) {
+ _field = field;
+ }
+
+ @Override
+ void deserialize(AbstractHessianInput in, Object obj)
+ throws IOException {
+ java.sql.Time value = null;
+
+ try {
+ java.util.Date date = (java.util.Date) in.readObject();
+ if (date != null) value = new java.sql.Time(date.getTime());
+
+ _field.set(obj, value);
+ } catch (Exception e) {
+ logDeserializeError(_field, obj, value, e);
+ }
+ }
+ }
+
+ /**
+ * @see java.lang.Boolean#TYPE
+ * @see java.lang.Character#TYPE
+ * @see java.lang.Byte#TYPE
+ * @see java.lang.Short#TYPE
+ * @see java.lang.Integer#TYPE
+ * @see java.lang.Long#TYPE
+ * @see java.lang.Float#TYPE
+ * @see java.lang.Double#TYPE
+ * @see java.lang.Void#TYPE
+ */
+ private static boolean isPrimitive(Type type) {
+ try {
+ if (type != null) {
+ if (type instanceof Class<?>) {
+ Class<?> clazz = (Class<?>) type;
+ return clazz.isPrimitive()
+ || PRIMITIVE_TYPE.containsKey(clazz.getName());
+ }
+ }
+ } catch (Exception e) {
+ // ignore exception
+ }
+ return false;
+ }
+
+ static final Map<String, Boolean> PRIMITIVE_TYPE = new HashMap<String, Boolean>() {
+ {
+ put(Boolean.class.getName(), true);
+ put(Character.class.getName(), true);
+ put(Byte.class.getName(), true);
+ put(Short.class.getName(), true);
+ put(Integer.class.getName(), true);
+ put(Long.class.getName(), true);
+ put(Float.class.getName(), true);
+ put(Double.class.getName(), true);
+ put(Void.class.getName(), true);
+ }
+ };
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/JavaSerializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/JavaSerializer.java
new file mode 100644
index 0000000..4e53245
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/JavaSerializer.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Serializing an object for known object types.
+ */
+public class JavaSerializer extends AbstractSerializer {
+ private static final Logger log
+ = Logger.getLogger(JavaSerializer.class.getName());
+
+ private static Object[] NULL_ARGS = new Object[0];
+
+ private Field[] _fields;
+ private FieldSerializer[] _fieldSerializers;
+
+ private Object _writeReplaceFactory;
+ private Method _writeReplace;
+
+ public JavaSerializer(Class cl, ClassLoader loader) {
+ introspectWriteReplace(cl, loader);
+
+ if (_writeReplace != null)
+ _writeReplace.setAccessible(true);
+
+ List primitiveFields = new ArrayList();
+ List compoundFields = new ArrayList();
+
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Field[] fields = cl.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+
+ if (Modifier.isTransient(field.getModifiers())
+ || Modifier.isStatic(field.getModifiers()))
+ continue;
+
+ // XXX: could parameterize the handler to only deal with public
+ field.setAccessible(true);
+
+ if (field.getType().isPrimitive()
+ || (field.getType().getName().startsWith("java.lang.")
+ && !field.getType().equals(Object.class)))
+ primitiveFields.add(field);
+ else
+ compoundFields.add(field);
+ }
+ }
+
+ List fields = new ArrayList();
+ fields.addAll(primitiveFields);
+ fields.addAll(compoundFields);
+ Collections.reverse(fields);
+
+ _fields = new Field[fields.size()];
+ fields.toArray(_fields);
+
+ _fieldSerializers = new FieldSerializer[_fields.length];
+
+ for (int i = 0; i < _fields.length; i++) {
+ _fieldSerializers[i] = getFieldSerializer(_fields[i].getType());
+ }
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected static Method getWriteReplace(Class cl) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (int i = 0; i < methods.length; i++) {
+ Method method = methods[i];
+
+ if (method.getName().equals("writeReplace") &&
+ method.getParameterTypes().length == 0)
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ private static FieldSerializer getFieldSerializer(Class type) {
+ if (int.class.equals(type)
+ || byte.class.equals(type)
+ || short.class.equals(type)
+ || int.class.equals(type)) {
+ return IntFieldSerializer.SER;
+ } else if (long.class.equals(type)) {
+ return LongFieldSerializer.SER;
+ } else if (double.class.equals(type) ||
+ float.class.equals(type)) {
+ return DoubleFieldSerializer.SER;
+ } else if (boolean.class.equals(type)) {
+ return BooleanFieldSerializer.SER;
+ } else if (String.class.equals(type)) {
+ return StringFieldSerializer.SER;
+ } else if (java.util.Date.class.equals(type)
+ || java.sql.Date.class.equals(type)
+ || java.sql.Timestamp.class.equals(type)
+ || java.sql.Time.class.equals(type)) {
+ return DateFieldSerializer.SER;
+ } else
+ return FieldSerializer.SER;
+ }
+
+ private void introspectWriteReplace(Class cl, ClassLoader loader) {
+ try {
+ String className = cl.getName() + "HessianSerializer";
+
+ Class serializerClass = Class.forName(className, false, loader);
+
+ Object serializerObject = serializerClass.newInstance();
+
+ Method writeReplace = getWriteReplace(serializerClass, cl);
+
+ if (writeReplace != null) {
+ _writeReplaceFactory = serializerObject;
+ _writeReplace = writeReplace;
+
+ return;
+ }
+ } catch (ClassNotFoundException e) {
+ } catch (Exception e) {
+ log.log(Level.FINER, e.toString(), e);
+ }
+
+ _writeReplace = getWriteReplace(cl);
+ }
+
+ /**
+ * Returns the writeReplace method
+ */
+ protected Method getWriteReplace(Class cl, Class param) {
+ for (; cl != null; cl = cl.getSuperclass()) {
+ for (Method method : cl.getDeclaredMethods()) {
+ if (method.getName().equals("writeReplace")
+ && method.getParameterTypes().length == 1
+ && param.equals(method.getParameterTypes()[0]))
+ return method;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ if (out.addRef(obj)) {
+ return;
+ }
+
+ Class cl = obj.getClass();
+
+ try {
+ if (_writeReplace != null) {
+ Object repl;
+
+ if (_writeReplaceFactory != null)
+ repl = _writeReplace.invoke(_writeReplaceFactory, obj);
+ else
+ repl = _writeReplace.invoke(obj);
+
+ //Some class would return itself for wrapReplace, which would cause infinite recursion
+ //In this case, we could write the object just like normal cases
+ if (repl != obj) {
+ out.removeRef(obj);
+
+ out.writeObject(repl);
+
+ out.replaceRef(repl, obj);
+
+ return;
+ }
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ // log.log(Level.FINE, e.toString(), e);
+ throw new RuntimeException(e);
+ }
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ writeObject10(obj, out);
+ } else {
+ if (ref == -1) {
+ writeDefinition20(out);
+ out.writeObjectBegin(cl.getName());
+ }
+
+ writeInstance(obj, out);
+ }
+ }
+
+ private void writeObject10(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ out.writeString(field.getName());
+
+ _fieldSerializers[i].serialize(out, obj, field);
+ }
+
+ out.writeMapEnd();
+ }
+
+ private void writeDefinition20(AbstractHessianOutput out)
+ throws IOException {
+ out.writeClassFieldLength(_fields.length);
+
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ out.writeString(field.getName());
+ }
+ }
+
+ public void writeInstance(Object obj, AbstractHessianOutput out)
+ throws IOException {
+ for (int i = 0; i < _fields.length; i++) {
+ Field field = _fields[i];
+
+ _fieldSerializers[i].serialize(out, obj, field);
+ }
+ }
+
+ static class FieldSerializer {
+ static final FieldSerializer SER = new FieldSerializer();
+
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ Object value = null;
+
+ try {
+ value = field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ try {
+ out.writeObject(value);
+ } catch (RuntimeException e) {
+ throw new RuntimeException(e.getMessage() + "\n Java field: " + field,
+ e);
+ } catch (IOException e) {
+ throw new IOExceptionWrapper(e.getMessage() + "\n Java field: " + field,
+ e);
+ }
+ }
+ }
+
+ static class BooleanFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new BooleanFieldSerializer();
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ boolean value = false;
+
+ try {
+ value = field.getBoolean(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeBoolean(value);
+ }
+ }
+
+ static class IntFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new IntFieldSerializer();
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ int value = 0;
+
+ try {
+ value = field.getInt(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeInt(value);
+ }
+ }
+
+ static class LongFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new LongFieldSerializer();
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ long value = 0;
+
+ try {
+ value = field.getLong(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeLong(value);
+ }
+ }
+
+ static class DoubleFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new DoubleFieldSerializer();
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ double value = 0;
+
+ try {
+ value = field.getDouble(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeDouble(value);
+ }
+ }
+
+ static class StringFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new StringFieldSerializer();
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ String value = null;
+
+ try {
+ value = (String) field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ out.writeString(value);
+ }
+ }
+
+ static class DateFieldSerializer extends FieldSerializer {
+ static final FieldSerializer SER = new DateFieldSerializer();
+
+ @Override
+ void serialize(AbstractHessianOutput out, Object obj, Field field)
+ throws IOException {
+ java.util.Date value = null;
+
+ try {
+ value = (java.util.Date) field.get(obj);
+ } catch (IllegalAccessException e) {
+ log.log(Level.FINE, e.toString(), e);
+ }
+
+ if (value == null)
+ out.writeNull();
+ else
+ out.writeUTCDate(value.getTime());
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/LocaleHandle.java
similarity index 65%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/LocaleHandle.java
index 72a9822..322e9d4 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/LocaleHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,20 +46,45 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
-import java.io.IOException;
+import java.util.Locale;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Handle for a locale object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
- @Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+public class LocaleHandle implements java.io.Serializable, HessianHandle {
+ private String value;
+
+ public LocaleHandle(String locale) {
+ this.value = locale;
+ }
+
+ private Object readResolve() {
+ if (value == null) {
+ return null;
+ }
+
+ if (value.length() == 0) {
+ return new Locale("");
+ }
+
+ int extStart = value.indexOf("_#");
+ if (extStart != -1) value = value.substring(0, extStart);
+
+ String language = value, country = "", variant = "";
+ int pos1 = value.indexOf('_');
+ if (pos1 != -1) {
+ language = value.substring(0, pos1++);
+
+ int pos2 = value.indexOf('_', pos1);
+ if (pos2 == -1) {
+ country = value.substring(pos1);
+ } else {
+ country = value.substring(pos1, pos2);
+ variant = value.substring(pos2 + 1);
+ }
+ }
+ return new Locale(language, country, variant);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/LocaleSerializer.java
similarity index 79%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/LocaleSerializer.java
index 72a9822..70142fa 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/LocaleSerializer.java
@@ -46,20 +46,30 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.Locale;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a locale.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class LocaleSerializer extends AbstractSerializer {
+ private static LocaleSerializer SERIALIZER = new LocaleSerializer();
+
+ public static LocaleSerializer create() {
+ return SERIALIZER;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ Locale locale = (Locale) obj;
+
+ out.writeObject(new LocaleHandle(locale.toString()));
+ }
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/MapDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/MapDeserializer.java
new file mode 100644
index 0000000..4c0a88d
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/MapDeserializer.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Deserializing a JDK 1.2 Map.
+ */
+public class MapDeserializer extends AbstractMapDeserializer {
+ private Class _type;
+ private Constructor _ctor;
+
+ public MapDeserializer(Class type) {
+ if (type == null)
+ type = HashMap.class;
+
+ _type = type;
+
+ Constructor[] ctors = type.getConstructors();
+ for (int i = 0; i < ctors.length; i++) {
+ if (ctors[i].getParameterTypes().length == 0)
+ _ctor = ctors[i];
+ }
+
+ if (_ctor == null) {
+ try {
+ _ctor = HashMap.class.getConstructor(new Class[0]);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ @Override
+ public Class getType() {
+ if (_type != null)
+ return _type;
+ else
+ return HashMap.class;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ return readMap(in, null, null);
+ }
+
+ /**
+ * support generic type of map, fix the type of short serialization <p>
+ * eg: Map<String, Short> serialize & deserialize
+ *
+ */
+ @Override
+ public Object readMap(AbstractHessianInput in, Class<?> expectKeyType, Class<?> expectValueType) throws IOException {
+ Map map;
+
+ if (_type == null)
+ map = new HashMap();
+ else if (_type.equals(Map.class))
+ map = new HashMap();
+ else if (_type.equals(SortedMap.class))
+ map = new TreeMap();
+ else {
+ try {
+ map = (Map) _ctor.newInstance();
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+
+ in.addRef(map);
+
+ doReadMap(in, map, expectKeyType, expectValueType);
+
+ in.readEnd();
+
+ return map;
+ }
+
+ protected void doReadMap(AbstractHessianInput in, Map map, Class<?> keyType, Class<?> valueType) throws IOException {
+ Deserializer keyDeserializer = null, valueDeserializer = null;
+
+ SerializerFactory factory = findSerializerFactory(in);
+ if(keyType != null){
+ keyDeserializer = factory.getDeserializer(keyType.getName());
+ }
+ if(valueType != null){
+ valueDeserializer = factory.getDeserializer(valueType.getName());
+ }
+
+ while (!in.isEnd()) {
+ map.put(keyDeserializer != null ? keyDeserializer.readObject(in) : in.readObject(),
+ valueDeserializer != null? valueDeserializer.readObject(in) : in.readObject());
+ }
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in,
+ String[] fieldNames)
+ throws IOException {
+ Map map = createMap();
+
+ int ref = in.addRef(map);
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String name = fieldNames[i];
+
+ map.put(name, in.readObject());
+ }
+
+ return map;
+ }
+
+ private Map createMap()
+ throws IOException {
+
+ if (_type == null)
+ return new HashMap();
+ else if (_type.equals(Map.class))
+ return new HashMap();
+ else if (_type.equals(SortedMap.class))
+ return new TreeMap();
+ else {
+ try {
+ return (Map) _ctor.newInstance();
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/MapSerializer.java
similarity index 62%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/MapSerializer.java
index 72a9822..7c2e4e8 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/MapSerializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,57 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a JDK 1.2 java.util.Map.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
+public class MapSerializer extends AbstractSerializer {
+ private boolean _isSendJavaType = true;
+
/**
- * Looks up a proxy object.
+ * Return true if the java type of the collection should be sent.
*/
+ public boolean getSendJavaType() {
+ return _isSendJavaType;
+ }
+
+ /**
+ * Set true if the java type of the collection should be sent.
+ */
+ public void setSendJavaType(boolean sendJavaType) {
+ _isSendJavaType = sendJavaType;
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (out.addRef(obj))
+ return;
+
+ Map map = (Map) obj;
+
+ Class cl = obj.getClass();
+
+ if (cl.equals(HashMap.class)
+ || !_isSendJavaType
+ || !(obj instanceof java.io.Serializable))
+ out.writeMapBegin(null);
+ else
+ out.writeMapBegin(obj.getClass().getName());
+
+ Iterator iter = map.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Map.Entry) iter.next();
+
+ out.writeObject(entry.getKey());
+ out.writeObject(entry.getValue());
+ }
+ out.writeMapEnd();
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ObjectDeserializer.java
similarity index 64%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/ObjectDeserializer.java
index 7c8e328..4a75bb7 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/BeanSerializerFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ObjectDeserializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
*
* The Apache Software License, Version 1.1
*
@@ -46,35 +46,51 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
/**
- * Factory for returning serialization methods.
+ * Serializing an object for known object types.
*/
-public class BeanSerializerFactory extends SerializerFactory {
- /**
- * Returns the default serializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
- */
- @Override
- protected Serializer getDefaultSerializer(Class cl) {
- return new BeanSerializer(cl, getClassLoader());
+public class ObjectDeserializer extends AbstractDeserializer {
+ private Class _cl;
+
+ public ObjectDeserializer(Class cl) {
+ _cl = cl;
}
- /**
- * Returns the default deserializer for a class that isn't matched
- * directly. Application can override this method to produce
- * bean-style serialization instead of field serialization.
- *
- * @param cl the class of the object that needs to be serialized.
- * @return a serializer object for the serialization.
- */
@Override
- protected Deserializer getDefaultDeserializer(Class cl) {
- return new BeanDeserializer(cl);
+ public Class getType() {
+ return _cl;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in)
+ throws IOException {
+ return in.readObject();
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readList(AbstractHessianInput in, int length)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public Object readLengthList(AbstractHessianInput in, int length)
+ throws IOException {
+ throw new UnsupportedOperationException(String.valueOf(this));
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[" + _cl + "]";
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/RemoteSerializer.java
similarity index 86%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/RemoteSerializer.java
index 72a9822..8f49dce 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/RemoteSerializer.java
@@ -46,20 +46,18 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a remote object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class RemoteSerializer extends AbstractSerializer {
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ // XXX: needs to be handled as a separate class
+ throw new UnsupportedOperationException(getClass().getName());
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/Serializer.java
similarity index 87%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/Serializer.java
index be505fb..d675fc0 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/EnvelopeFactory.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/Serializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,11 +46,14 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
-import java.util.logging.Logger;
+import java.io.IOException;
-public class EnvelopeFactory {
- private static final Logger log
- = Logger.getLogger(EnvelopeFactory.class.getName());
+/**
+ * Serializing an object.
+ */
+public interface Serializer {
+ public void writeObject(Object obj, AbstractHessianOutput out)
+ throws IOException;
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/SerializerFactory.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/SerializerFactory.java
new file mode 100644
index 0000000..b513ef0
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/SerializerFactory.java
@@ -0,0 +1,722 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import com.alibaba.com.caucho.hessian3.io.java8.DurationHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.InstantHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.LocalDateHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.LocalDateTimeHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.LocalTimeHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.MonthDayHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.OffsetDateTimeHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.OffsetTimeHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.PeriodHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.YearHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.YearMonthHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.ZoneIdSerializer;
+import com.alibaba.com.caucho.hessian3.io.java8.ZoneOffsetHandle;
+import com.alibaba.com.caucho.hessian3.io.java8.ZonedDateTimeHandle;
+
+import javax.management.ObjectName;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static com.alibaba.com.caucho.hessian3.io.java8.Java8TimeSerializer.create;
+
+/**
+ * Factory for returning serialization methods.
+ */
+public class SerializerFactory extends AbstractSerializerFactory {
+ private static final Logger log
+ = Logger.getLogger(SerializerFactory.class.getName());
+
+ private static Deserializer OBJECT_DESERIALIZER
+ = new BasicDeserializer(BasicDeserializer.OBJECT);
+ private static ConcurrentHashMap _unrecognizedTypeCache = new ConcurrentHashMap();
+ private static HashMap _staticSerializerMap;
+ private static HashMap _staticDeserializerMap;
+ private static HashMap _staticTypeMap;
+
+ static {
+ _staticSerializerMap = new HashMap();
+ _staticDeserializerMap = new HashMap();
+ _staticTypeMap = new HashMap();
+
+ addBasic(void.class, "void", BasicSerializer.NULL);
+
+ addBasic(Boolean.class, "boolean", BasicSerializer.BOOLEAN);
+ addBasic(Byte.class, "byte", BasicSerializer.BYTE);
+ addBasic(Short.class, "short", BasicSerializer.SHORT);
+ addBasic(Integer.class, "int", BasicSerializer.INTEGER);
+ addBasic(Long.class, "long", BasicSerializer.LONG);
+ addBasic(Float.class, "float", BasicSerializer.FLOAT);
+ addBasic(Double.class, "double", BasicSerializer.DOUBLE);
+ addBasic(Character.class, "char", BasicSerializer.CHARACTER_OBJECT);
+ addBasic(String.class, "string", BasicSerializer.STRING);
+ addBasic(Object.class, "object", BasicSerializer.OBJECT);
+ addBasic(java.util.Date.class, "date", BasicSerializer.DATE);
+
+ addBasic(boolean.class, "boolean", BasicSerializer.BOOLEAN);
+ addBasic(byte.class, "byte", BasicSerializer.BYTE);
+ addBasic(short.class, "short", BasicSerializer.SHORT);
+ addBasic(int.class, "int", BasicSerializer.INTEGER);
+ addBasic(long.class, "long", BasicSerializer.LONG);
+ addBasic(float.class, "float", BasicSerializer.FLOAT);
+ addBasic(double.class, "double", BasicSerializer.DOUBLE);
+ addBasic(char.class, "char", BasicSerializer.CHARACTER);
+
+ addBasic(boolean[].class, "[boolean", BasicSerializer.BOOLEAN_ARRAY);
+ addBasic(byte[].class, "[byte", BasicSerializer.BYTE_ARRAY);
+ addBasic(short[].class, "[short", BasicSerializer.SHORT_ARRAY);
+ addBasic(int[].class, "[int", BasicSerializer.INTEGER_ARRAY);
+ addBasic(long[].class, "[long", BasicSerializer.LONG_ARRAY);
+ addBasic(float[].class, "[float", BasicSerializer.FLOAT_ARRAY);
+ addBasic(double[].class, "[double", BasicSerializer.DOUBLE_ARRAY);
+ addBasic(char[].class, "[char", BasicSerializer.CHARACTER_ARRAY);
+ addBasic(String[].class, "[string", BasicSerializer.STRING_ARRAY);
+ addBasic(Object[].class, "[object", BasicSerializer.OBJECT_ARRAY);
+
+ _staticSerializerMap.put(Class.class, new ClassSerializer());
+
+ _staticDeserializerMap.put(Number.class, new BasicDeserializer(BasicSerializer.NUMBER));
+
+ _staticSerializerMap.put(BigDecimal.class, new StringValueSerializer());
+ try {
+ _staticDeserializerMap.put(BigDecimal.class,
+ new StringValueDeserializer(BigDecimal.class));
+ _staticDeserializerMap.put(BigInteger.class,
+ new BigIntegerDeserializer());
+ } catch (Throwable e) {
+ }
+
+
+ _staticSerializerMap.put(UUID.class, new StringValueSerializer());
+ _staticDeserializerMap.put(UUID.class, new UUIDDeserializer());
+
+ _staticSerializerMap.put(File.class, new StringValueSerializer());
+ try {
+ _staticDeserializerMap.put(File.class,
+ new StringValueDeserializer(File.class));
+ } catch (Throwable e) {
+ }
+
+ _staticSerializerMap.put(ObjectName.class, new StringValueSerializer());
+ try {
+ _staticDeserializerMap.put(ObjectName.class,
+ new StringValueDeserializer(ObjectName.class));
+ } catch (Throwable e) {
+ }
+
+ _staticSerializerMap.put(java.sql.Date.class, new SqlDateSerializer());
+ _staticSerializerMap.put(java.sql.Time.class, new SqlDateSerializer());
+ _staticSerializerMap.put(java.sql.Timestamp.class, new SqlDateSerializer());
+
+ _staticSerializerMap.put(java.io.InputStream.class,
+ new InputStreamSerializer());
+ _staticDeserializerMap.put(java.io.InputStream.class,
+ new InputStreamDeserializer());
+
+ try {
+ _staticDeserializerMap.put(java.sql.Date.class,
+ new SqlDateDeserializer(java.sql.Date.class));
+ _staticDeserializerMap.put(java.sql.Time.class,
+ new SqlDateDeserializer(java.sql.Time.class));
+ _staticDeserializerMap.put(java.sql.Timestamp.class,
+ new SqlDateDeserializer(java.sql.Timestamp.class));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+
+ // hessian/3bb5
+ try {
+ Class stackTrace = StackTraceElement.class;
+
+ _staticDeserializerMap.put(stackTrace, new StackTraceElementDeserializer());
+ } catch (Throwable e) {
+ }
+
+ try {
+ if (isJava8()) {
+ _staticSerializerMap.put(Class.forName("java.time.LocalTime"), create(LocalTimeHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.LocalDate"), create(LocalDateHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.LocalDateTime"), create(LocalDateTimeHandle.class));
+
+ _staticSerializerMap.put(Class.forName("java.time.Instant"), create(InstantHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.Duration"), create(DurationHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.Period"), create(PeriodHandle.class));
+
+ _staticSerializerMap.put(Class.forName("java.time.Year"), create(YearHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.YearMonth"), create(YearMonthHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.MonthDay"), create(MonthDayHandle.class));
+
+ _staticSerializerMap.put(Class.forName("java.time.OffsetDateTime"), create(OffsetDateTimeHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.ZoneOffset"), create(ZoneOffsetHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.OffsetTime"), create(OffsetTimeHandle.class));
+ _staticSerializerMap.put(Class.forName("java.time.ZonedDateTime"), create(ZonedDateTimeHandle.class));
+ }
+ } catch (Throwable t) {
+ log.warning(String.valueOf(t.getCause()));
+ }
+ }
+
+ protected Serializer _defaultSerializer;
+
+ // Additional factories
+ protected ArrayList _factories = new ArrayList();
+
+ protected CollectionSerializer _collectionSerializer;
+ protected MapSerializer _mapSerializer;
+ private ClassLoader _loader;
+ private Deserializer _hashMapDeserializer;
+ private Deserializer _arrayListDeserializer;
+ private ConcurrentHashMap _cachedSerializerMap;
+ private ConcurrentHashMap _cachedDeserializerMap;
+ private ConcurrentHashMap _cachedTypeDeserializerMap;
+ private boolean _isAllowNonSerializable;
+ /**
+ * For those classes are unknown in current classloader, record them in this set to avoid
+ * frequently class loading and to reduce performance overhead.
+ */
+ private Map<String, Object> _typeNotFoundDeserializerMap = new ConcurrentHashMap<>(8);
+ private static final Object PRESENT = new Object();
+
+ private ClassFactory _classFactory;
+
+ public SerializerFactory() {
+ this(Thread.currentThread().getContextClassLoader());
+ }
+
+ public SerializerFactory(ClassLoader loader) {
+ _loader = loader;
+ }
+
+ public Class<?> loadSerializedClass(String className)
+ throws ClassNotFoundException
+ {
+ return getClassFactory().load(className);
+ }
+
+ public ClassFactory getClassFactory()
+ {
+ synchronized (this) {
+ if (_classFactory == null) {
+ _classFactory = new ClassFactory(getClassLoader());
+ }
+
+ return _classFactory;
+ }
+ }
+
+ private static void addBasic(Class cl, String typeName, int type) {
+ _staticSerializerMap.put(cl, new BasicSerializer(type));
+
+ Deserializer deserializer = new BasicDeserializer(type);
+ _staticDeserializerMap.put(cl, deserializer);
+ _staticTypeMap.put(typeName, deserializer);
+ }
+
+ public ClassLoader getClassLoader() {
+ return _loader;
+ }
+
+ /**
+ * Set true if the collection serializer should send the java type.
+ */
+ public void setSendCollectionType(boolean isSendType) {
+ if (_collectionSerializer == null)
+ _collectionSerializer = new CollectionSerializer();
+
+ _collectionSerializer.setSendJavaType(isSendType);
+
+ if (_mapSerializer == null)
+ _mapSerializer = new MapSerializer();
+
+ _mapSerializer.setSendJavaType(isSendType);
+ }
+
+ /**
+ * Adds a factory.
+ */
+ public void addFactory(AbstractSerializerFactory factory) {
+ _factories.add(factory);
+ }
+
+ /**
+ * If true, non-serializable objects are allowed.
+ */
+ public boolean isAllowNonSerializable() {
+ return _isAllowNonSerializable;
+ }
+
+ /**
+ * If true, non-serializable objects are allowed.
+ */
+ public void setAllowNonSerializable(boolean allow) {
+ _isAllowNonSerializable = allow;
+ }
+
+ /**
+ * Returns the serializer for a class.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ * @return a serializer object for the serialization.
+ */
+ @Override
+ public Serializer getSerializer(Class cl)
+ throws HessianProtocolException {
+ Serializer serializer;
+
+ serializer = (Serializer) _staticSerializerMap.get(cl);
+ if (serializer != null) {
+ return serializer;
+ }
+
+ if (_cachedSerializerMap != null) {
+ serializer = (Serializer) _cachedSerializerMap.get(cl);
+ if (serializer != null) {
+ return serializer;
+ }
+ }
+
+ for (int i = 0;
+ serializer == null && _factories != null && i < _factories.size();
+ i++) {
+ AbstractSerializerFactory factory;
+
+ factory = (AbstractSerializerFactory) _factories.get(i);
+
+ serializer = factory.getSerializer(cl);
+ }
+
+ if (serializer != null) {
+
+ } else if (isZoneId(cl)) //must before "else if (JavaSerializer.getWriteReplace(cl) != null)"
+ serializer = ZoneIdSerializer.getInstance();
+ else if (isEnumSet(cl))
+ serializer = EnumSetSerializer.getInstance();
+ else if (JavaSerializer.getWriteReplace(cl) != null)
+ serializer = new JavaSerializer(cl, _loader);
+
+ else if (HessianRemoteObject.class.isAssignableFrom(cl))
+ serializer = new RemoteSerializer();
+
+// else if (BurlapRemoteObject.class.isAssignableFrom(cl))
+// serializer = new RemoteSerializer();
+
+ else if (Map.class.isAssignableFrom(cl)) {
+ if (_mapSerializer == null)
+ _mapSerializer = new MapSerializer();
+
+ serializer = _mapSerializer;
+ } else if (Collection.class.isAssignableFrom(cl)) {
+ if (_collectionSerializer == null) {
+ _collectionSerializer = new CollectionSerializer();
+ }
+
+ serializer = _collectionSerializer;
+ } else if (cl.isArray()) {
+ serializer = new ArraySerializer();
+ } else if (Throwable.class.isAssignableFrom(cl)) {
+ serializer = new ThrowableSerializer(cl, getClassLoader());
+ } else if (InputStream.class.isAssignableFrom(cl)) {
+ serializer = new InputStreamSerializer();
+ } else if (Iterator.class.isAssignableFrom(cl)) {
+ serializer = IteratorSerializer.create();
+ } else if (Enumeration.class.isAssignableFrom(cl)) {
+ serializer = EnumerationSerializer.create();
+ } else if (Calendar.class.isAssignableFrom(cl)) {
+ serializer = CalendarSerializer.create();
+ } else if (Locale.class.isAssignableFrom(cl)) {
+ serializer = LocaleSerializer.create();
+ } else if (Enum.class.isAssignableFrom(cl)) {
+ serializer = new EnumSerializer(cl);
+ } else if (BitSet.class.isAssignableFrom(cl)) {
+ serializer = BitSetSerializer.create();
+ }
+
+ if (serializer == null) {
+ serializer = getDefaultSerializer(cl);
+ }
+
+ if (_cachedSerializerMap == null) {
+ _cachedSerializerMap = new ConcurrentHashMap(8);
+ }
+
+ _cachedSerializerMap.put(cl, serializer);
+
+ return serializer;
+ }
+
+ /**
+ * Returns the default serializer for a class that isn't matched
+ * directly. Application can override this method to produce
+ * bean-style serialization instead of field serialization.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ * @return a serializer object for the serialization.
+ */
+ protected Serializer getDefaultSerializer(Class cl) {
+ if (_defaultSerializer != null)
+ return _defaultSerializer;
+
+ if (!Serializable.class.isAssignableFrom(cl)
+ && !_isAllowNonSerializable) {
+ throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");
+ }
+
+ return new JavaSerializer(cl, _loader);
+ }
+
+ /**
+ * Returns the deserializer for a class.
+ *
+ * @param cl the class of the object that needs to be deserialized.
+ * @return a deserializer object for the serialization.
+ */
+ @Override
+ public Deserializer getDeserializer(Class cl)
+ throws HessianProtocolException {
+ Deserializer deserializer;
+
+ deserializer = (Deserializer) _staticDeserializerMap.get(cl);
+ if (deserializer != null)
+ return deserializer;
+
+ if (_cachedDeserializerMap != null) {
+ deserializer = (Deserializer) _cachedDeserializerMap.get(cl);
+ if (deserializer != null)
+ return deserializer;
+ }
+
+
+ for (int i = 0;
+ deserializer == null && _factories != null && i < _factories.size();
+ i++) {
+ AbstractSerializerFactory factory;
+ factory = (AbstractSerializerFactory) _factories.get(i);
+
+ deserializer = factory.getDeserializer(cl);
+ }
+
+ if (deserializer != null) {
+ } else if (Collection.class.isAssignableFrom(cl))
+ deserializer = new CollectionDeserializer(cl);
+
+ else if (Map.class.isAssignableFrom(cl))
+ deserializer = new MapDeserializer(cl);
+
+ else if (cl.isInterface())
+ deserializer = new ObjectDeserializer(cl);
+
+ else if (cl.isArray())
+ deserializer = new ArrayDeserializer(cl.getComponentType());
+
+ else if (Enumeration.class.isAssignableFrom(cl))
+ deserializer = EnumerationDeserializer.create();
+
+ else if (Enum.class.isAssignableFrom(cl))
+ deserializer = new EnumDeserializer(cl);
+
+ else if (Class.class.equals(cl))
+ deserializer = new ClassDeserializer(_loader);
+
+ else
+ deserializer = getDefaultDeserializer(cl);
+
+ if (_cachedDeserializerMap == null)
+ _cachedDeserializerMap = new ConcurrentHashMap(8);
+
+ _cachedDeserializerMap.put(cl, deserializer);
+
+ return deserializer;
+ }
+
+ /**
+ * Returns the default serializer for a class that isn't matched
+ * directly. Application can override this method to produce
+ * bean-style serialization instead of field serialization.
+ *
+ * @param cl the class of the object that needs to be serialized.
+ * @return a serializer object for the serialization.
+ */
+ protected Deserializer getDefaultDeserializer(Class cl) {
+ if (!Serializable.class.isAssignableFrom(cl)
+ && !_isAllowNonSerializable) {
+ throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");
+ }
+
+ return new JavaDeserializer(cl);
+ }
+
+ /**
+ * Reads the object as a list.
+ */
+ public Object readList(AbstractHessianInput in, int length, String type)
+ throws HessianProtocolException, IOException {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer.readList(in, length);
+ else
+ return new CollectionDeserializer(ArrayList.class).readList(in, length);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Object readMap(AbstractHessianInput in, String type)
+ throws HessianProtocolException, IOException {
+ return readMap(in, type, null, null);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Object readMap(AbstractHessianInput in, String type, Class<?> expectKeyType, Class<?> expectValueType)
+ throws HessianProtocolException, IOException {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer.readMap(in);
+ else if (_hashMapDeserializer != null)
+ return _hashMapDeserializer.readMap(in, expectKeyType, expectValueType);
+ else {
+ _hashMapDeserializer = new MapDeserializer(HashMap.class);
+
+ return _hashMapDeserializer.readMap(in, expectKeyType, expectValueType);
+ }
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Object readObject(AbstractHessianInput in,
+ String type,
+ String[] fieldNames)
+ throws HessianProtocolException, IOException {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer.readObject(in, fieldNames);
+ else if (_hashMapDeserializer != null)
+ return _hashMapDeserializer.readObject(in, fieldNames);
+ else {
+ _hashMapDeserializer = new MapDeserializer(HashMap.class);
+
+ return _hashMapDeserializer.readObject(in, fieldNames);
+ }
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getObjectDeserializer(String type, Class cl)
+ throws HessianProtocolException {
+ Deserializer reader = getObjectDeserializer(type);
+
+ if (cl == null
+ || cl.equals(reader.getType())
+ || cl.isAssignableFrom(reader.getType())
+ || HessianHandle.class.isAssignableFrom(reader.getType())) {
+ return reader;
+ }
+
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("hessian: expected '" + cl.getName() + "' at '" + type + "' ("
+ + reader.getType().getName() + ")");
+ }
+
+ return getDeserializer(cl);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getObjectDeserializer(String type)
+ throws HessianProtocolException {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer;
+ else if (_hashMapDeserializer != null)
+ return _hashMapDeserializer;
+ else {
+ _hashMapDeserializer = new MapDeserializer(HashMap.class);
+
+ return _hashMapDeserializer;
+ }
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getListDeserializer(String type, Class cl)
+ throws HessianProtocolException {
+ Deserializer reader = getListDeserializer(type);
+
+ if (cl == null
+ || cl.equals(reader.getType())
+ || cl.isAssignableFrom(reader.getType())) {
+ return reader;
+ }
+
+ if (log.isLoggable(Level.FINE)) {
+ log.fine("hessian: expected '" + cl.getName() + "' at '" + type + "' ("
+ + reader.getType().getName() + ")");
+ }
+
+ return getDeserializer(cl);
+ }
+
+ /**
+ * Reads the object as a map.
+ */
+ public Deserializer getListDeserializer(String type)
+ throws HessianProtocolException {
+ Deserializer deserializer = getDeserializer(type);
+
+ if (deserializer != null)
+ return deserializer;
+ else if (_arrayListDeserializer != null)
+ return _arrayListDeserializer;
+ else {
+ _arrayListDeserializer = new CollectionDeserializer(ArrayList.class);
+
+ return _arrayListDeserializer;
+ }
+ }
+
+ /**
+ * Returns a deserializer based on a string type.
+ */
+ public Deserializer getDeserializer(String type)
+ throws HessianProtocolException {
+ if (type == null || type.equals("") || _typeNotFoundDeserializerMap.containsKey(type))
+ return null;
+
+ Deserializer deserializer;
+
+ if (_cachedTypeDeserializerMap != null) {
+ deserializer = (Deserializer) _cachedTypeDeserializerMap.get(type);
+
+ if (deserializer != null)
+ return deserializer;
+ }
+
+
+ deserializer = (Deserializer) _staticTypeMap.get(type);
+ if (deserializer != null)
+ return deserializer;
+
+ if (type.startsWith("[")) {
+ Deserializer subDeserializer = getDeserializer(type.substring(1));
+
+ if (subDeserializer != null)
+ deserializer = new ArrayDeserializer(subDeserializer.getType());
+ else
+ deserializer = new ArrayDeserializer(Object.class);
+ } else if (_unrecognizedTypeCache.get(type) == null) {
+ try {
+// Class cl = Class.forName(type, false, _loader);
+ Class cl = loadSerializedClass(type);
+ deserializer = getDeserializer(cl);
+ } catch (Exception e) {
+ log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
+ _typeNotFoundDeserializerMap.put(type, PRESENT);
+ log.log(Level.FINER, e.toString(), e);
+ _unrecognizedTypeCache.put(type, new AtomicLong(1L));
+ }
+ } else {
+ ((AtomicLong) _unrecognizedTypeCache.get(type)).incrementAndGet();
+ if (((AtomicLong) _unrecognizedTypeCache.get(type)).get() % 2000L == 0L)
+ ((AtomicLong) _unrecognizedTypeCache.get(type)).getAndSet(1L);
+ }
+
+ if (deserializer != null) {
+ if (_cachedTypeDeserializerMap == null)
+ _cachedTypeDeserializerMap = new ConcurrentHashMap(8);
+
+ _cachedTypeDeserializerMap.put(type, deserializer);
+ }
+
+ return deserializer;
+ }
+
+ private static boolean isZoneId(Class cl) {
+ try {
+ return isJava8() && Class.forName("java.time.ZoneId").isAssignableFrom(cl);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ return false;
+ }
+
+ private static boolean isEnumSet(Class cl) {
+ return EnumSet.class.isAssignableFrom(cl);
+ }
+
+ /**
+ * check if the environment is java 8 or beyond
+ *
+ * @return if on java 8
+ */
+ private static boolean isJava8() {
+ String javaVersion = System.getProperty("java.specification.version");
+ return Double.valueOf(javaVersion) >= 1.8;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/SqlDateDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/SqlDateDeserializer.java
new file mode 100644
index 0000000..f9c5660
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/SqlDateDeserializer.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+
+/**
+ * Deserializing a string valued object
+ */
+public class SqlDateDeserializer extends AbstractDeserializer {
+ private Class _cl;
+ private Constructor _constructor;
+
+ public SqlDateDeserializer(Class cl)
+ throws NoSuchMethodException {
+ _cl = cl;
+ _constructor = cl.getConstructor(new Class[]{long.class});
+ }
+
+ @Override
+ public Class getType() {
+ return _cl;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ int ref = in.addRef(null);
+
+ long initValue = Long.MIN_VALUE;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ initValue = in.readUTCDate();
+ else
+ in.readString();
+ }
+
+ in.readMapEnd();
+
+ Object value = create(initValue);
+
+ in.setRef(ref, value);
+
+ return value;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ int ref = in.addRef(null);
+
+ long initValue = Long.MIN_VALUE;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ String key = fieldNames[i];
+
+ if (key.equals("value"))
+ initValue = in.readUTCDate();
+ else
+ in.readObject();
+ }
+
+ Object value = create(initValue);
+
+ in.setRef(ref, value);
+
+ return value;
+ }
+
+ private Object create(long initValue)
+ throws IOException {
+ if (initValue == Long.MIN_VALUE)
+ throw new IOException(_cl.getName() + " expects name.");
+
+ try {
+ return _constructor.newInstance(new Object[]{new Long(initValue)});
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/SqlDateSerializer.java
similarity index 71%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/SqlDateSerializer.java
index 72a9822..067960d 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/SqlDateSerializer.java
@@ -46,20 +46,41 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
+import java.util.Date;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a sql date object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class SqlDateSerializer extends AbstractSerializer {
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ Class cl = obj.getClass();
+
+ if (out.addRef(obj))
+ return;
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ out.writeString("value");
+ out.writeUTCDate(((Date) obj).getTime());
+ out.writeMapEnd();
+ } else {
+ if (ref == -1) {
+ out.writeInt(1);
+ out.writeString("value");
+ out.writeObjectBegin(cl.getName());
+ }
+
+ out.writeUTCDate(((Date) obj).getTime());
+ }
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/StackTraceElementDeserializer.java
similarity index 84%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/StackTraceElementDeserializer.java
index 72a9822..234d790 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/StackTraceElementDeserializer.java
@@ -46,20 +46,19 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
-
-import java.io.IOException;
+package com.alibaba.com.caucho.hessian3.io;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing a JDK 1.4 StackTraceElement
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class StackTraceElementDeserializer extends JavaDeserializer {
+ public StackTraceElementDeserializer() {
+ super(StackTraceElement.class);
+ }
+
@Override
- public Object lookup(String type, String url)
- throws IOException {
- return new HessianRemote(type, url);
+ protected Object instantiate()
+ throws Exception {
+ return new StackTraceElement("", "", "", 0);
}
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/StringValueDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/StringValueDeserializer.java
new file mode 100644
index 0000000..fbab268
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/StringValueDeserializer.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.io;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+
+/**
+ * Deserializing a string valued object
+ */
+public class StringValueDeserializer extends AbstractDeserializer {
+ private Class _cl;
+ private Constructor _constructor;
+
+ public StringValueDeserializer(Class cl) {
+ try {
+ _cl = cl;
+ _constructor = cl.getConstructor(new Class[]{String.class});
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Class getType() {
+ return _cl;
+ }
+
+ @Override
+ public Object readMap(AbstractHessianInput in)
+ throws IOException {
+ String value = null;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ value = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ Object object = create(value);
+
+ in.addRef(object);
+
+ return object;
+ }
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ String value = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i]))
+ value = in.readString();
+ else
+ in.readObject();
+ }
+
+ Object object = create(value);
+
+ in.addRef(object);
+
+ return object;
+ }
+
+ private Object create(String value)
+ throws IOException {
+ if (value == null)
+ throw new IOException(_cl.getName() + " expects name.");
+
+ try {
+ return _constructor.newInstance(new Object[]{value});
+ } catch (Exception e) {
+ throw new IOExceptionWrapper(e);
+ }
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/StringValueSerializer.java
similarity index 72%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/StringValueSerializer.java
index 72a9822..90c82f4 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/StringValueSerializer.java
@@ -46,20 +46,40 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing a remote object.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class StringValueSerializer extends AbstractSerializer {
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ if (obj == null)
+ out.writeNull();
+ else {
+ if (out.addRef(obj))
+ return;
+
+ Class cl = obj.getClass();
+
+ int ref = out.writeObjectBegin(cl.getName());
+
+ if (ref < -1) {
+ out.writeString("value");
+ out.writeString(obj.toString());
+ out.writeMapEnd();
+ } else {
+ if (ref == -1) {
+ out.writeInt(1);
+ out.writeString("value");
+ out.writeObjectBegin(cl.getName());
+ }
+
+ out.writeString(obj.toString());
+ }
+ }
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ThrowableSerializer.java
similarity index 81%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/ThrowableSerializer.java
index 72a9822..287497a 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ThrowableSerializer.java
@@ -22,7 +22,7 @@
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
- * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
* endorse or promote products derived from this software without prior
* written permission. For written permission, please contact
* info@caucho.com.
@@ -46,20 +46,25 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Serializing an object for known object types.
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+public class ThrowableSerializer extends JavaSerializer {
+ public ThrowableSerializer(Class cl, ClassLoader loader) {
+ super(cl, loader);
+ }
+
@Override
- public Object lookup(String type, String url)
+ public void writeObject(Object obj, AbstractHessianOutput out)
throws IOException {
- return new HessianRemote(type, url);
+ Throwable e = (Throwable) obj;
+
+ e.getStackTrace();
+
+ super.writeObject(obj, out);
}
}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/UUIDDeserializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/UUIDDeserializer.java
similarity index 92%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/UUIDDeserializer.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/UUIDDeserializer.java
index ffe1fca..229968c 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/UUIDDeserializer.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/UUIDDeserializer.java
@@ -1,4 +1,4 @@
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
import java.util.UUID;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/ValueDeserializer.java
similarity index 69%
copy from src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
copy to src/test/java/com/alibaba/com/caucho/hessian3/io/ValueDeserializer.java
index 72a9822..76ab5a2 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/AbstractHessianResolver.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/ValueDeserializer.java
@@ -46,20 +46,48 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.io;
+package com.alibaba.com.caucho.hessian3.io;
import java.io.IOException;
/**
- * Looks up remote objects. The default just returns a HessianRemote object.
+ * Deserializing a string valued object
*/
-public class AbstractHessianResolver implements HessianRemoteResolver {
- /**
- * Looks up a proxy object.
- */
+abstract public class ValueDeserializer extends AbstractDeserializer {
@Override
- public Object lookup(String type, String url)
+ public Object readMap(AbstractHessianInput in)
throws IOException {
- return new HessianRemote(type, url);
+ String initValue = null;
+
+ while (!in.isEnd()) {
+ String key = in.readString();
+
+ if (key.equals("value"))
+ initValue = in.readString();
+ else
+ in.readObject();
+ }
+
+ in.readMapEnd();
+
+ return create(initValue);
}
+
+ @Override
+ public Object readObject(AbstractHessianInput in, String[] fieldNames)
+ throws IOException {
+ String initValue = null;
+
+ for (int i = 0; i < fieldNames.length; i++) {
+ if ("value".equals(fieldNames[i]))
+ initValue = in.readString();
+ else
+ in.readObject();
+ }
+
+ return create(initValue);
+ }
+
+ abstract Object create(String value)
+ throws IOException;
}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/DurationHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/DurationHandle.java
new file mode 100755
index 0000000..e06f57d
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/DurationHandle.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+
+@SuppressWarnings("unchecked")
+public class DurationHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -4367309317780077156L;
+
+ private long seconds;
+ private int nanos;
+
+ public DurationHandle() {
+ }
+
+ public DurationHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.Duration");
+ Method m = c.getDeclaredMethod("getSeconds");
+ this.seconds = (Long) m.invoke(o);
+ m = c.getDeclaredMethod("getNano");
+ this.nanos = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.Duration");
+ Method m = c.getDeclaredMethod("ofSeconds", long.class, long.class);
+ return m.invoke(null, seconds, nanos);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/InstantHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/InstantHandle.java
new file mode 100755
index 0000000..060c855
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/InstantHandle.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class InstantHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -4367309317780077156L;
+
+ private long seconds;
+ private int nanos;
+
+ public InstantHandle() {
+ }
+
+ public InstantHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.Instant");
+ Method m = c.getDeclaredMethod("getEpochSecond");
+ this.seconds = (Long) m.invoke(o);
+ m = c.getDeclaredMethod("getNano");
+ this.nanos = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.Instant");
+ Method m = c.getDeclaredMethod("ofEpochSecond", long.class, long.class);
+ return m.invoke(null, seconds, nanos);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/io/java8/Java8TimeSerializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/Java8TimeSerializer.java
similarity index 90%
rename from src/main/java/com/alibaba/com/caucho/hessian/io/java8/Java8TimeSerializer.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/io/java8/Java8TimeSerializer.java
index dcc09ec..32af662 100755
--- a/src/main/java/com/alibaba/com/caucho/hessian/io/java8/Java8TimeSerializer.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/Java8TimeSerializer.java
@@ -15,13 +15,13 @@
* limitations under the License.
*/
-package com.alibaba.com.caucho.hessian.io.java8;
+package com.alibaba.com.caucho.hessian3.io.java8;
import java.io.IOException;
import java.lang.reflect.Constructor;
-import com.alibaba.com.caucho.hessian.io.AbstractHessianOutput;
-import com.alibaba.com.caucho.hessian.io.AbstractSerializer;
+import com.alibaba.com.caucho.hessian3.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian3.io.AbstractSerializer;
public class Java8TimeSerializer<T> extends AbstractSerializer {
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalDateHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalDateHandle.java
new file mode 100755
index 0000000..541d920
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalDateHandle.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class LocalDateHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = 166018689500019951L;
+
+ private int year;
+ private int month;
+ private int day;
+
+ public LocalDateHandle() {
+ }
+
+ public LocalDateHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.LocalDate");
+ Method m = c.getDeclaredMethod("getYear");
+ this.year = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getMonthValue");
+ this.month = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getDayOfMonth");
+ this.day = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ public Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.LocalDate");
+ Method m = c.getDeclaredMethod("of", int.class, int.class, int.class);
+ return m.invoke(null, year, month, day);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalDateTimeHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalDateTimeHandle.java
new file mode 100755
index 0000000..042fd24
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalDateTimeHandle.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class LocalDateTimeHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = 7563825215275989361L;
+
+ private Object date;
+ private Object time;
+
+ public LocalDateTimeHandle() {
+ }
+
+ public LocalDateTimeHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.LocalDateTime");
+ Method m = c.getDeclaredMethod("toLocalDate");
+ date = m.invoke(o);
+ m = c.getDeclaredMethod("toLocalTime");
+ time = m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.LocalDateTime");
+ Method m = c.getDeclaredMethod("of", Class.forName("java.time.LocalDate"),
+ Class.forName("java.time.LocalTime"));
+ return m.invoke(null, date, time);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalTimeHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalTimeHandle.java
new file mode 100755
index 0000000..695c278
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/LocalTimeHandle.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class LocalTimeHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -5892919085390462315L;
+
+ private int hour;
+ private int minute;
+ private int second;
+ private int nano;
+
+ public LocalTimeHandle() {
+ }
+
+ public LocalTimeHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.LocalTime");
+ Method m = c.getDeclaredMethod("getHour");
+ this.hour = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getMinute");
+ this.minute = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getSecond");
+ this.second = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getNano");
+ this.nano = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.LocalTime");
+ Method m = c.getDeclaredMethod("of", int.class, int.class, int.class, int.class);
+ return m.invoke(null, hour, minute, second, nano);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/MonthDayHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/MonthDayHandle.java
new file mode 100755
index 0000000..c27b390
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/MonthDayHandle.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class MonthDayHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = 5288238558666577745L;
+
+ private int month;
+ private int day;
+
+ public MonthDayHandle() {
+ }
+
+ public MonthDayHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.MonthDay");
+ Method m = c.getDeclaredMethod("getMonthValue");
+ this.month = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getDayOfMonth");
+ this.day = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.MonthDay");
+ Method m = c.getDeclaredMethod("of", int.class, int.class);
+ return m.invoke(null, month, day);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/OffsetDateTimeHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/OffsetDateTimeHandle.java
new file mode 100755
index 0000000..4330a2e
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/OffsetDateTimeHandle.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class OffsetDateTimeHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -7823900532640515312L;
+
+ private Object dateTime;
+ private Object offset;
+
+ public OffsetDateTimeHandle() {
+ }
+
+ public OffsetDateTimeHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.OffsetDateTime");
+ Method m = c.getDeclaredMethod("toLocalDateTime");
+ this.dateTime = m.invoke(o);
+ m = c.getDeclaredMethod("getOffset");
+ this.offset = m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+
+ try {
+ Class c = Class.forName("java.time.OffsetDateTime");
+ Method m = c.getDeclaredMethod("of", Class.forName("java.time.LocalDateTime"),
+ Class.forName("java.time.ZoneOffset"));
+ return m.invoke(null, dateTime, offset);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/OffsetTimeHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/OffsetTimeHandle.java
new file mode 100755
index 0000000..8d17080
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/OffsetTimeHandle.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class OffsetTimeHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -3269846941421652860L;
+
+ private Object localTime;
+ private Object zoneOffset;
+
+ public OffsetTimeHandle() {
+ }
+
+ public OffsetTimeHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.OffsetTime");
+ Method m = c.getDeclaredMethod("getOffset");
+ this.zoneOffset = m.invoke(o);
+ m = c.getDeclaredMethod("toLocalTime");
+ this.localTime = m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.OffsetTime");
+ Method m = c.getDeclaredMethod("of", Class.forName("java.time.LocalTime"),
+ Class.forName("java.time.ZoneOffset"));
+ return m.invoke(null, localTime, zoneOffset);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/PeriodHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/PeriodHandle.java
new file mode 100755
index 0000000..b02893d
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/PeriodHandle.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+
+@SuppressWarnings("unchecked")
+public class PeriodHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = 4399720381283781186L;
+
+ private int years;
+ private int months;
+ private int days;
+
+ public PeriodHandle() {
+ }
+
+ public PeriodHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.Period");
+ Method m = c.getDeclaredMethod("getYears");
+ this.years = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getMonths");
+ this.months = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getDays");
+ this.days = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.Period");
+ Method m = c.getDeclaredMethod("of", int.class, int.class, int.class);
+ return m.invoke(null, years, months, days);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/YearHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/YearHandle.java
new file mode 100755
index 0000000..99544fd
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/YearHandle.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class YearHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -6299552890287487926L;
+
+ private int year;
+
+ public YearHandle() {
+ }
+
+ public YearHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.Year");
+ Method m = c.getDeclaredMethod("getValue");
+ this.year = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.Year");
+ Method m = c.getDeclaredMethod("of", int.class);
+ return m.invoke(null, year);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/YearMonthHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/YearMonthHandle.java
new file mode 100755
index 0000000..7ae3cf3
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/YearMonthHandle.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class YearMonthHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -4150786187896925314L;
+
+ private int year;
+ private int month;
+
+ public YearMonthHandle() {
+ }
+
+ public YearMonthHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.YearMonth");
+ Method m = c.getDeclaredMethod("getYear");
+ this.year = (Integer) m.invoke(o);
+ m = c.getDeclaredMethod("getMonthValue");
+ this.month = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.YearMonth");
+ Method m = c.getDeclaredMethod("of", int.class, int.class);
+ return m.invoke(null, year, month);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneIdHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneIdHandle.java
new file mode 100755
index 0000000..97d722d
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneIdHandle.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class ZoneIdHandle implements HessianHandle, Serializable {
+
+ private static final long serialVersionUID = 8789182864066905552L;
+
+ private String zoneId;
+
+ public ZoneIdHandle() {
+ }
+
+ public ZoneIdHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.ZoneId");
+ Method m = c.getDeclaredMethod("getId");
+ this.zoneId = (String) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.ZoneId");
+ Method m = c.getDeclaredMethod("of", String.class);
+ return m.invoke(null, this.zoneId);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneIdSerializer.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneIdSerializer.java
new file mode 100755
index 0000000..dbf3363
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneIdSerializer.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.AbstractHessianOutput;
+import com.alibaba.com.caucho.hessian3.io.AbstractSerializer;
+
+import java.io.IOException;
+
+public class ZoneIdSerializer extends AbstractSerializer {
+
+ private static final ZoneIdSerializer SERIALIZER = new ZoneIdSerializer();
+
+ public static ZoneIdSerializer getInstance() {
+ return SERIALIZER;
+ }
+
+ @Override
+ public void writeObject(Object obj, AbstractHessianOutput out) throws IOException {
+ if (obj == null) {
+ out.writeNull();
+ } else {
+ out.writeObject(new ZoneIdHandle(obj));
+ }
+ }
+
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneOffsetHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneOffsetHandle.java
new file mode 100755
index 0000000..d25dcb8
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZoneOffsetHandle.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class ZoneOffsetHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = 8841589723587858789L;
+
+ private int seconds;
+
+ public ZoneOffsetHandle() {
+ }
+
+ public ZoneOffsetHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.ZoneOffset");
+ Method m = c.getDeclaredMethod("getTotalSeconds");
+ this.seconds = (Integer) m.invoke(o);
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class c = Class.forName("java.time.ZoneOffset");
+ Method m = c.getDeclaredMethod("ofTotalSeconds", int.class);
+ return m.invoke(null, seconds);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZonedDateTimeHandle.java b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZonedDateTimeHandle.java
new file mode 100755
index 0000000..4ab5100
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/io/java8/ZonedDateTimeHandle.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.com.caucho.hessian3.io.java8;
+
+import com.alibaba.com.caucho.hessian3.io.HessianHandle;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+@SuppressWarnings("unchecked")
+public class ZonedDateTimeHandle implements HessianHandle, Serializable {
+ private static final long serialVersionUID = -6933460123278647569L;
+
+ private Object dateTime;
+ private Object offset;
+ private String zoneId;
+
+
+ public ZonedDateTimeHandle() {
+ }
+
+ public ZonedDateTimeHandle(Object o) {
+ try {
+ Class c = Class.forName("java.time.ZonedDateTime");
+ Method m = c.getDeclaredMethod("toLocalDateTime");
+ this.dateTime = m.invoke(o);
+ m = c.getDeclaredMethod("getOffset");
+ this.offset = m.invoke(o);
+ m = c.getDeclaredMethod("getZone");
+ Object zone = m.invoke(o);
+ if (zone != null) {
+ Class zoneId = Class.forName("java.time.ZoneId");
+ m = zoneId.getDeclaredMethod("getId");
+ this.zoneId = (String) m.invoke(zone);
+ }
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+ private Object readResolve() {
+ try {
+ Class zoneDateTime = Class.forName("java.time.ZonedDateTime");
+ Method ofLocal = zoneDateTime.getDeclaredMethod("ofLocal", Class.forName("java.time.LocalDateTime"),
+ Class.forName("java.time.ZoneId"), Class.forName("java.time.ZoneOffset"));
+ Class c = Class.forName("java.time.ZoneId");
+ Method of = c.getDeclaredMethod("of", String.class);
+ return ofLocal.invoke(null, dateTime, of.invoke(null, this.zoneId), offset);
+ } catch (Throwable t) {
+ // ignore
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/security/X509Encryption.java b/src/test/java/com/alibaba/com/caucho/hessian3/security/X509Encryption.java
similarity index 97%
rename from src/main/java/com/alibaba/com/caucho/hessian/security/X509Encryption.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/security/X509Encryption.java
index 2156cec..12c61ee 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/security/X509Encryption.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/security/X509Encryption.java
@@ -46,11 +46,11 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.security;
+package com.alibaba.com.caucho.hessian3.security;
-import com.alibaba.com.caucho.hessian.io.Hessian2Input;
-import com.alibaba.com.caucho.hessian.io.Hessian2Output;
-import com.alibaba.com.caucho.hessian.io.HessianEnvelope;
+import com.alibaba.com.caucho.hessian3.io.Hessian2Input;
+import com.alibaba.com.caucho.hessian3.io.Hessian2Output;
+import com.alibaba.com.caucho.hessian3.io.HessianEnvelope;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
diff --git a/src/main/java/com/alibaba/com/caucho/hessian/security/X509Signature.java b/src/test/java/com/alibaba/com/caucho/hessian3/security/X509Signature.java
similarity index 97%
rename from src/main/java/com/alibaba/com/caucho/hessian/security/X509Signature.java
rename to src/test/java/com/alibaba/com/caucho/hessian3/security/X509Signature.java
index a8023e7..208e5a9 100644
--- a/src/main/java/com/alibaba/com/caucho/hessian/security/X509Signature.java
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/security/X509Signature.java
@@ -46,11 +46,11 @@
* @author Scott Ferguson
*/
-package com.alibaba.com.caucho.hessian.security;
+package com.alibaba.com.caucho.hessian3.security;
-import com.alibaba.com.caucho.hessian.io.Hessian2Input;
-import com.alibaba.com.caucho.hessian.io.Hessian2Output;
-import com.alibaba.com.caucho.hessian.io.HessianEnvelope;
+import com.alibaba.com.caucho.hessian3.io.Hessian2Input;
+import com.alibaba.com.caucho.hessian3.io.Hessian2Output;
+import com.alibaba.com.caucho.hessian3.io.HessianEnvelope;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/util/IdentityIntMap.java b/src/test/java/com/alibaba/com/caucho/hessian3/util/IdentityIntMap.java
new file mode 100644
index 0000000..24a038a
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/util/IdentityIntMap.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.util;
+
+/**
+ * The IntMap provides a simple hashmap from keys to integers. The API is
+ * an abbreviation of the HashMap collection API.
+ * <p>
+ * <p>The convenience of IntMap is avoiding all the silly wrapping of
+ * integers.
+ */
+public class IdentityIntMap {
+ /**
+ * Encoding of a null entry. Since NULL is equal to Integer.MIN_VALUE,
+ * it's impossible to distinguish between the two.
+ */
+ public final static int NULL = 0xdeadbeef; // Integer.MIN_VALUE + 1;
+
+ private static final Object DELETED = new Object();
+
+ private Object[] _keys;
+ private int[] _values;
+
+ private int _size;
+ private int _mask;
+
+ /**
+ * Create a new IntMap. Default size is 16.
+ */
+ public IdentityIntMap() {
+ _keys = new Object[256];
+ _values = new int[256];
+
+ _mask = _keys.length - 1;
+ _size = 0;
+ }
+
+ /**
+ * Clear the hashmap.
+ */
+ public void clear() {
+ Object[] keys = _keys;
+ int[] values = _values;
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ keys[i] = null;
+ values[i] = 0;
+ }
+
+ _size = 0;
+ }
+
+ /**
+ * Returns the current number of entries in the map.
+ */
+ public int size() {
+ return _size;
+ }
+
+ /**
+ * Puts a new value in the property table with the appropriate flags
+ */
+ public int get(Object key) {
+ int mask = _mask;
+ int hash = System.identityHashCode(key) % mask & mask;
+
+ Object[] keys = _keys;
+
+ while (true) {
+ Object mapKey = keys[hash];
+
+ if (mapKey == null)
+ return NULL;
+ else if (mapKey == key)
+ return _values[hash];
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ /**
+ * Expands the property table
+ */
+ private void resize(int newSize) {
+ Object[] newKeys = new Object[newSize];
+ int[] newValues = new int[newSize];
+
+ int mask = _mask = newKeys.length - 1;
+
+ Object[] keys = _keys;
+ int values[] = _values;
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ Object key = keys[i];
+
+ if (key == null || key == DELETED)
+ continue;
+
+ int hash = System.identityHashCode(key) % mask & mask;
+
+ while (true) {
+ if (newKeys[hash] == null) {
+ newKeys[hash] = key;
+ newValues[hash] = values[i];
+ break;
+ }
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ _keys = newKeys;
+ _values = newValues;
+ }
+
+ /**
+ * Puts a new value in the property table with the appropriate flags
+ */
+ public int put(Object key, int value) {
+ int mask = _mask;
+ int hash = System.identityHashCode(key) % mask & mask;
+
+ Object[] keys = _keys;
+
+ while (true) {
+ Object testKey = keys[hash];
+
+ if (testKey == null || testKey == DELETED) {
+ keys[hash] = key;
+ _values[hash] = value;
+
+ _size++;
+
+ if (keys.length <= 4 * _size)
+ resize(4 * keys.length);
+
+ return NULL;
+ } else if (key != testKey) {
+ hash = (hash + 1) % mask;
+
+ continue;
+ } else {
+ int old = _values[hash];
+
+ _values[hash] = value;
+
+ return old;
+ }
+ }
+ }
+
+ /**
+ * Deletes the entry. Returns true if successful.
+ */
+ public int remove(Object key) {
+ int mask = _mask;
+ int hash = System.identityHashCode(key) % mask & mask;
+
+ while (true) {
+ Object mapKey = _keys[hash];
+
+ if (mapKey == null)
+ return NULL;
+ else if (mapKey == key) {
+ _keys[hash] = DELETED;
+
+ _size--;
+
+ return _values[hash];
+ }
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sbuf = new StringBuffer();
+
+ sbuf.append("IntMap[");
+ boolean isFirst = true;
+
+ for (int i = 0; i <= _mask; i++) {
+ if (_keys[i] != null && _keys[i] != DELETED) {
+ if (!isFirst)
+ sbuf.append(", ");
+
+ isFirst = false;
+ sbuf.append(_keys[i]);
+ sbuf.append(":");
+ sbuf.append(_values[i]);
+ }
+ }
+ sbuf.append("]");
+
+ return sbuf.toString();
+ }
+}
diff --git a/src/test/java/com/alibaba/com/caucho/hessian3/util/IntMap.java b/src/test/java/com/alibaba/com/caucho/hessian3/util/IntMap.java
new file mode 100644
index 0000000..850b8f6
--- /dev/null
+++ b/src/test/java/com/alibaba/com/caucho/hessian3/util/IntMap.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2001-2008 Caucho Technology, Inc. All rights reserved.
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Caucho Technology (http://www.caucho.com/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * info@caucho.com.
+ *
+ * 5. Products derived from this software may not be called "Resin"
+ * nor may "Resin" appear in their names without prior written
+ * permission of Caucho Technology.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
+ *
+ * @author Scott Ferguson
+ */
+
+package com.alibaba.com.caucho.hessian3.util;
+
+/**
+ * The IntMap provides a simple hashmap from keys to integers. The API is
+ * an abbreviation of the HashMap collection API.
+ * <p>
+ * <p>The convenience of IntMap is avoiding all the silly wrapping of
+ * integers.
+ */
+public class IntMap {
+ /**
+ * Encoding of a null entry. Since NULL is equal to Integer.MIN_VALUE,
+ * it's impossible to distinguish between the two.
+ */
+ public final static int NULL = 0xdeadbeef; // Integer.MIN_VALUE + 1;
+
+ private static final Object DELETED = new Object();
+
+ private Object[] _keys;
+ private int[] _values;
+
+ private int _size;
+ private int _mask;
+
+ /**
+ * Create a new IntMap. Default size is 16.
+ */
+ public IntMap() {
+ _keys = new Object[256];
+ _values = new int[256];
+
+ _mask = _keys.length - 1;
+ _size = 0;
+ }
+
+ /**
+ * Clear the hashmap.
+ */
+ public void clear() {
+ Object[] keys = _keys;
+ int[] values = _values;
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ keys[i] = null;
+ values[i] = 0;
+ }
+
+ _size = 0;
+ }
+
+ /**
+ * Returns the current number of entries in the map.
+ */
+ public int size() {
+ return _size;
+ }
+
+ /**
+ * Puts a new value in the property table with the appropriate flags
+ */
+ public int get(Object key) {
+ int mask = _mask;
+ int hash = key.hashCode() % mask & mask;
+
+ Object[] keys = _keys;
+
+ while (true) {
+ Object mapKey = keys[hash];
+
+ if (mapKey == null)
+ return NULL;
+ else if (mapKey == key || mapKey.equals(key))
+ return _values[hash];
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ /**
+ * Expands the property table
+ */
+ private void resize(int newSize) {
+ Object[] newKeys = new Object[newSize];
+ int[] newValues = new int[newSize];
+
+ int mask = _mask = newKeys.length - 1;
+
+ Object[] keys = _keys;
+ int values[] = _values;
+
+ for (int i = keys.length - 1; i >= 0; i--) {
+ Object key = keys[i];
+
+ if (key == null || key == DELETED)
+ continue;
+
+ int hash = key.hashCode() % mask & mask;
+
+ while (true) {
+ if (newKeys[hash] == null) {
+ newKeys[hash] = key;
+ newValues[hash] = values[i];
+ break;
+ }
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ _keys = newKeys;
+ _values = newValues;
+ }
+
+ /**
+ * Puts a new value in the property table with the appropriate flags
+ */
+ public int put(Object key, int value) {
+ int mask = _mask;
+ int hash = key.hashCode() % mask & mask;
+
+ Object[] keys = _keys;
+
+ while (true) {
+ Object testKey = keys[hash];
+
+ if (testKey == null || testKey == DELETED) {
+ keys[hash] = key;
+ _values[hash] = value;
+
+ _size++;
+
+ if (keys.length <= 4 * _size)
+ resize(4 * keys.length);
+
+ return NULL;
+ } else if (key != testKey && !key.equals(testKey)) {
+ hash = (hash + 1) % mask;
+
+ continue;
+ } else {
+ int old = _values[hash];
+
+ _values[hash] = value;
+
+ return old;
+ }
+ }
+ }
+
+ /**
+ * Deletes the entry. Returns true if successful.
+ */
+ public int remove(Object key) {
+ int mask = _mask;
+ int hash = key.hashCode() % mask & mask;
+
+ while (true) {
+ Object mapKey = _keys[hash];
+
+ if (mapKey == null)
+ return NULL;
+ else if (mapKey == key) {
+ _keys[hash] = DELETED;
+
+ _size--;
+
+ return _values[hash];
+ }
+
+ hash = (hash + 1) % mask;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sbuf = new StringBuffer();
+
+ sbuf.append("IntMap[");
+ boolean isFirst = true;
+
+ for (int i = 0; i <= _mask; i++) {
+ if (_keys[i] != null && _keys[i] != DELETED) {
+ if (!isFirst)
+ sbuf.append(", ");
+
+ isFirst = false;
+ sbuf.append(_keys[i]);
+ sbuf.append(":");
+ sbuf.append(_values[i]);
+ }
+ }
+ sbuf.append("]");
+
+ return sbuf.toString();
+ }
+}