diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java index b89d9942..b6c81535 100644 --- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/ContextSerializerFactory.java @@ -55,12 +55,7 @@ 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.*; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -234,7 +229,7 @@ public static ContextSerializerFactory create(ClassLoader loader) { } } - private static void addBasic(Class cl, String typeName, int type) { + public static void addBasic(Class cl, String typeName, int type) { _staticSerializerMap.put(cl.getName(), new BasicSerializer(type)); Deserializer deserializer = new BasicDeserializer(type); diff --git a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java index cbe92bf1..a96c9837 100644 --- a/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java +++ b/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/InputStreamDeserializer.java @@ -48,20 +48,78 @@ package com.alibaba.com.caucho.hessian.io; -import java.io.IOException; +import java.io.*; +import java.util.UUID; /** + * InputStream Deserializer * Serializing a stream object. + * @author HeYuJie + * @date 2024/10/31 */ public class InputStreamDeserializer extends AbstractDeserializer { public static final InputStreamDeserializer DESER = new InputStreamDeserializer(); + // TODO Allow external configuration + @SuppressWarnings("FieldCanBeLocal") + private final int bufferSize = Hessian2Output.SIZE; + // TODO Allow external configuration + private final File tmpDir; + public InputStreamDeserializer() { + tmpDir = new File(System.getProperty("java.io.tmpdir"), "dubbo-"+ System.currentTimeMillis()); + if(!tmpDir.exists()){ + //noinspection ResultOfMethodCallIgnored + tmpDir.mkdirs(); + } } - public Object readObject(AbstractHessianInput in) - throws IOException { - return in.readInputStream(); + public Object readObject(AbstractHessianInput in) throws IOException { + + FileOutputStream out = null; + try { + @SuppressWarnings("resource") + InputStream input = in.readInputStream(); + // Read twice the size of the buffer (16k) + byte[] bytes = new byte[bufferSize * 2]; + File file = null; + while (true) { // Loop reading + + int len = input.read(bytes, 0, bytes.length); + + if (out == null) { + + // If the length of InputStream is less than the buffer, creating a byte stream returns + if (len <= bufferSize) { + byte[] buff = new byte[len]; + System.arraycopy(bytes, 0, buff, 0, len); + return new ByteArrayInputStream(buff); + } + + // If the length of InputStream is greater than the buffer, create a temporary file and return it + String name = String.format("%d-%s.dubbo.tmp", System.currentTimeMillis(), UUID.randomUUID().toString().replace("-", "")); + file = new File(tmpDir, name); + // Close the stream in finally + //noinspection resource + out = new FileOutputStream(file); + } + + // Exit when reading to the end + if (len == -1) { + break; + } + out.write(bytes, 0 ,len); + } + + out.flush(); + //noinspection IOStreamConstructor + return new FileInputStream(file); + } finally { + if (out != null){ + out.close(); + } + } } + } diff --git a/java-8-test/src/test/java/com/alibaba/com/caucho/hessian/io/HessianInputStreamDeserializerTest.java b/java-8-test/src/test/java/com/alibaba/com/caucho/hessian/io/HessianInputStreamDeserializerTest.java new file mode 100644 index 00000000..7cd94f18 --- /dev/null +++ b/java-8-test/src/test/java/com/alibaba/com/caucho/hessian/io/HessianInputStreamDeserializerTest.java @@ -0,0 +1,142 @@ +/* + * 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 org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledForJreRange; +import org.junit.jupiter.api.condition.JRE; + +import java.io.*; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +/** + * InputStreamDeserializer test + * @author HeYuJie + * @date 2024/10/31 + */ +public class HessianInputStreamDeserializerTest extends SerializeTestBase { + + protected T baseHessian2Serialize(T data) throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + Hessian2Output out = new Hessian2Output(bout); + + out.writeObject(data); + out.flush(); + + ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); + Hessian2Input input = new Hessian2Input(bin); + Object obj = input.readObject(InputStream.class); + return (T) obj; + } + + byte[] returnBytes(int size){ + byte[] bytes = new byte[size]; + Arrays.fill(bytes, (byte) 'A'); + bytes[0] = '&'; + bytes[bytes.length-3] = '$'; + bytes[bytes.length-2] = '%'; + bytes[bytes.length-1] = '#'; + return bytes; + } + + /** + * test 1024 byte + * deserialize return ByteArrayInputStream + */ + @Test + @EnabledForJreRange(max = JRE.JAVA_11) + public void test1024Byte() throws IOException { + int size = 1024; + byte[] bytes = returnBytes(size); + InputStream source = new ByteArrayInputStream(bytes); + InputStream result = baseHessian2Serialize(source); + + byte[] resultByte = new byte[size]; + result.read(resultByte); + + assertInstanceOf(ByteArrayInputStream.class, result, "type error"); + assertEquals(bytes.length, resultByte.length); + assertEquals(new String(bytes), new String(resultByte)); + } + + /** + * test 8192 byte + * deserialize return ByteArrayInputStream + */ + @Test + @EnabledForJreRange(max = JRE.JAVA_11) + public void test8192Byte() throws IOException { + int size = 8192; + byte[] bytes = returnBytes(size); + InputStream source = new ByteArrayInputStream(bytes); + InputStream result = baseHessian2Serialize(source); + + byte[] resultByte = new byte[size]; + result.read(resultByte); + + assertInstanceOf(ByteArrayInputStream.class, result, "type error"); + assertEquals(bytes.length, resultByte.length); + assertEquals(new String(bytes), new String(resultByte)); + } + + /** + * test 8193 byte + * One byte more than the buffer + * deserialize return FileInputStream + */ + @Test + @EnabledForJreRange(max = JRE.JAVA_11) + public void test8193Byte() throws IOException { + int size = 8193; + byte[] bytes = returnBytes(size); + InputStream source = new ByteArrayInputStream(bytes); + InputStream result = baseHessian2Serialize(source); + + byte[] resultByte = new byte[size]; + result.read(resultByte); + + assertInstanceOf(FileInputStream.class, result, "type error"); + assertEquals(bytes.length, resultByte.length); + assertEquals(new String(bytes), new String(resultByte)); + } + + /** + * test 81920 byte + * 10 times more bytes than the buffer + * deserialize return FileInputStream + */ + @Test + @EnabledForJreRange(max = JRE.JAVA_11) + public void test81920Byte() throws IOException { + int size = 81920; + byte[] bytes = returnBytes(size); + InputStream source = new ByteArrayInputStream(bytes); + InputStream result = baseHessian2Serialize(source); + + byte[] resultByte = new byte[size]; + result.read(resultByte); + + assertInstanceOf(FileInputStream.class, result, "type error"); + assertEquals(bytes.length, resultByte.length); + assertEquals(new String(bytes), new String(resultByte)); + } + +}