Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions java/fory-core/src/main/java/org/apache/fory/BaseFory.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
import org.apache.fory.io.ForyInputStream;
import org.apache.fory.io.ForyReadableChannel;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.reflect.TypeRef;
import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.BufferCallback;
import org.apache.fory.serializer.Serializer;
import org.apache.fory.serializer.SerializerFactory;
import org.apache.fory.serializer.Serializers;
import org.apache.fory.util.Preconditions;

/** All Fory’s basic interface, including Fory’s basic methods. */
public interface BaseFory {
Expand Down Expand Up @@ -234,6 +236,30 @@ void registerSerializerAndType(

<T> T deserialize(ForyReadableChannel channel, Class<T> type);

@SuppressWarnings("unchecked")
default <T> T deserialize(byte[] bytes, TypeRef<T> typeRef) {
Preconditions.checkNotNull(typeRef, "typeRef must not be null");
return deserialize(bytes, (Class<T>) typeRef.getRawType());
}

@SuppressWarnings("unchecked")
default <T> T deserialize(MemoryBuffer buffer, TypeRef<T> typeRef) {
Preconditions.checkNotNull(typeRef, "typeRef must not be null");
return deserialize(buffer, (Class<T>) typeRef.getRawType());
}

@SuppressWarnings("unchecked")
default <T> T deserialize(ForyInputStream inputStream, TypeRef<T> typeRef) {
Preconditions.checkNotNull(typeRef, "typeRef must not be null");
return deserialize(inputStream, (Class<T>) typeRef.getRawType());
}

@SuppressWarnings("unchecked")
default <T> T deserialize(ForyReadableChannel channel, TypeRef<T> typeRef) {
Preconditions.checkNotNull(typeRef, "typeRef must not be null");
return deserialize(channel, (Class<T>) typeRef.getRawType());
}

Object deserialize(byte[] bytes, Iterable<MemoryBuffer> outOfBandBuffers);

/** Deserialize <code>obj</code> from a <code>buffer</code>. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.fory.Fory;
import org.apache.fory.exception.DeserializationException;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.reflect.TypeRef;
import org.apache.fory.serializer.BufferCallback;
import org.apache.fory.util.ExceptionUtils;

Expand Down Expand Up @@ -82,6 +83,16 @@ public static <T> T deserialize(Fory fory, ReadableByteChannel channel, Class<T>
return type.cast(readFromChannel(fory, channel, b -> fory.deserialize(b, type)));
}

@SuppressWarnings("unchecked")
public static <T> T deserialize(Fory fory, InputStream inputStream, TypeRef<T> typeRef) {
return (T) deserializeFromStream(fory, inputStream, buf -> fory.deserialize(buf, typeRef));
}

@SuppressWarnings("unchecked")
public static <T> T deserialize(Fory fory, ReadableByteChannel channel, TypeRef<T> typeRef) {
return (T) readFromChannel(fory, channel, b -> fory.deserialize(b, typeRef));
}

private static Object readFromChannel(
Fory fory, ReadableByteChannel channel, Function<MemoryBuffer, Object> action) {
try {
Expand Down
84 changes: 84 additions & 0 deletions java/fory-core/src/test/java/org/apache/fory/ForyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.ByteArrayInputStream;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDate;
Expand All @@ -45,6 +47,8 @@
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
Expand All @@ -63,9 +67,12 @@
import org.apache.fory.exception.ForyException;
import org.apache.fory.exception.InsecureException;
import org.apache.fory.exception.SerializationException;
import org.apache.fory.io.ForyInputStream;
import org.apache.fory.io.ForyReadableChannel;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.memory.MemoryUtils;
import org.apache.fory.reflect.ReflectionUtils;
import org.apache.fory.reflect.TypeRef;
import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.ArraySerializersTest;
import org.apache.fory.serializer.EnumSerializerTest;
Expand Down Expand Up @@ -980,4 +987,81 @@ public void testMaxDepthCodegen() {
.build();
assertThrows(InsecureException.class, () -> fory.deserialize(bytes));
}

@Test
public void testDeserializeWithTypeRef() throws Exception {
Fory fory =
Fory.builder()
.requireClassRegistration(false)
.withXlang(false)
.withCompatible(false)
.build();

// 1. Root ArrayList<String> (exercises CollectionSerializer / CollectionLikeSerializer)
List<String> arrayList = new ArrayList<>(Arrays.asList("hello", "fory", "world"));
byte[] listBytes = fory.serialize(arrayList);
TypeRef<List<String>> listTypeRef = new TypeRef<List<String>>() {};

assertEquals(fory.deserialize(listBytes, listTypeRef), arrayList);
assertEquals(fory.deserialize(MemoryBuffer.fromByteArray(listBytes), listTypeRef), arrayList);

try (ForyInputStream stream = new ForyInputStream(new ByteArrayInputStream(listBytes))) {
assertEquals(fory.deserialize(stream, listTypeRef), arrayList);
}
try (ForyReadableChannel channel =
new ForyReadableChannel(Channels.newChannel(new ByteArrayInputStream(listBytes)))) {
assertEquals(fory.deserialize(channel, listTypeRef), arrayList);
}

// 2. Root LinkedList<String> and HashSet<String>
List<String> linkedList = new LinkedList<>(Arrays.asList("a", "b", "c"));
assertEquals(
fory.deserialize(fory.serialize(linkedList), new TypeRef<List<String>>() {}), linkedList);

Set<String> set = new HashSet<>(Arrays.asList("x", "y", "z"));
assertEquals(fory.deserialize(fory.serialize(set), new TypeRef<Set<String>>() {}), set);

// 3. Root Map<String, Integer> and nested Map<String, List<Integer>>
Map<String, Integer> intMap = new HashMap<>();
intMap.put("one", 1);
intMap.put("two", 2);
assertEquals(
fory.deserialize(fory.serialize(intMap), new TypeRef<Map<String, Integer>>() {}), intMap);

Map<String, List<Integer>> nestedMap = new HashMap<>();
nestedMap.put("key1", new ArrayList<>(Arrays.asList(1, 2, 3)));
nestedMap.put("key2", new ArrayList<>(Arrays.asList(4, 5, 6)));
byte[] mapBytes = fory.serialize(nestedMap);
TypeRef<Map<String, List<Integer>>> mapTypeRef = new TypeRef<Map<String, List<Integer>>>() {};
assertEquals(fory.deserialize(mapBytes, mapTypeRef), nestedMap);
assertEquals(fory.deserialize(MemoryBuffer.fromByteArray(mapBytes), mapTypeRef), nestedMap);

// 4. Arrays.asList view
List<String> asList = Arrays.asList("1", "2", "3");
assertEquals(fory.deserialize(fory.serialize(asList), new TypeRef<List<String>>() {}), asList);

// 5. Concrete object with TypeRef.of
BeanA beanA = BeanA.createBeanA(2);
byte[] beanBytes = fory.serialize(beanA);
assertEquals(fory.deserialize(beanBytes, TypeRef.of(BeanA.class)), beanA);

// 6. Null typeRef checks across all deserialize overloads
assertThrows(
NullPointerException.class,
() -> fory.deserialize(listBytes, (TypeRef<List<String>>) null));
assertThrows(
NullPointerException.class,
() ->
fory.deserialize(MemoryBuffer.fromByteArray(listBytes), (TypeRef<List<String>>) null));
try (ForyInputStream stream = new ForyInputStream(new ByteArrayInputStream(listBytes))) {
assertThrows(
NullPointerException.class, () -> fory.deserialize(stream, (TypeRef<List<String>>) null));
}
try (ForyReadableChannel channel =
new ForyReadableChannel(Channels.newChannel(new ByteArrayInputStream(listBytes)))) {
assertThrows(
NullPointerException.class,
() -> fory.deserialize(channel, (TypeRef<List<String>>) null));
}
}
}
18 changes: 18 additions & 0 deletions java/fory-core/src/test/java/org/apache/fory/StreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.apache.fory.io.ForyStreamReader;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.reflect.ReflectionUtils;
import org.apache.fory.reflect.TypeRef;
import org.apache.fory.test.bean.BeanA;
import org.testng.Assert;
import org.testng.annotations.Test;
Expand Down Expand Up @@ -272,6 +273,9 @@ public void testOutputStreamWithType() throws IOException {
assertEquals(newObj, beanA);
newObj = fory.deserialize(buf, BeanA.class);
assertEquals(newObj, beanA);
buf.readerIndex(0);
newObj = fory.deserialize(buf, new TypeRef<BeanA>() {});
assertEquals(newObj, beanA);
}

@Test
Expand Down Expand Up @@ -311,6 +315,20 @@ public void testReadableChannel() throws IOException {
Files.delete(tempFile);
}
}
{
ByteArrayOutputStream bas = new ByteArrayOutputStream();
fory.serialize(bas, beanA);

Path tempFile = Files.createTempFile("readable_channel_test", "data_3");
Files.write(tempFile, bas.toByteArray());

try (ForyReadableChannel channel = of(Files.newByteChannel(tempFile))) {
Object newObj = fory.deserialize(channel, new TypeRef<BeanA>() {});
assertEquals(newObj, beanA);
} finally {
Files.delete(tempFile);
}
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@
import static org.testng.Assert.assertSame;
import static org.testng.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
Expand All @@ -38,8 +45,11 @@
import org.apache.fory.context.ReadContext;
import org.apache.fory.context.WriteContext;
import org.apache.fory.exception.ForyException;
import org.apache.fory.io.ForyInputStream;
import org.apache.fory.io.ForyReadableChannel;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.pool.ThreadPoolFory;
import org.apache.fory.reflect.TypeRef;
import org.apache.fory.resolver.SharedRegistry;
import org.apache.fory.resolver.TypeResolver;
import org.apache.fory.serializer.Serializer;
Expand Down Expand Up @@ -425,6 +435,47 @@ public void testSerializeDeserializeWithType() {
}
}

@Test
public void testSerializeDeserializeWithTypeRef() throws Exception {
for (ThreadSafeFory fory :
new ThreadSafeFory[] {
Fory.builder()
.withXlang(false)
.requireClassRegistration(false)
.withCompatible(false)
.buildThreadSafeFory(),
Fory.builder()
.withXlang(false)
.requireClassRegistration(false)
.withCompatible(false)
.buildThreadSafeForyPool(2)
}) {
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
byte[] bytes = fory.serialize(list);
TypeRef<List<String>> typeRef = new TypeRef<List<String>>() {};
Assert.assertEquals(fory.deserialize(bytes, typeRef), list);
MemoryBuffer buffer = MemoryBuffer.newHeapBuffer(32);
fory.serialize(buffer, list);
Assert.assertEquals(fory.deserialize(buffer, typeRef), list);

try (ForyInputStream stream = new ForyInputStream(new ByteArrayInputStream(bytes))) {
Assert.assertEquals(fory.deserialize(stream, typeRef), list);
}
try (ForyReadableChannel channel =
new ForyReadableChannel(Channels.newChannel(new ByteArrayInputStream(bytes)))) {
Assert.assertEquals(fory.deserialize(channel, typeRef), list);
}

Map<String, Integer> map = new HashMap<>();
map.put("k1", 1);
map.put("k2", 2);
byte[] mapBytes = fory.serialize(map);
TypeRef<Map<String, Integer>> mapTypeRef = new TypeRef<Map<String, Integer>>() {};
Assert.assertEquals(fory.deserialize(mapBytes, mapTypeRef), map);
Assert.assertEquals(fory.deserialize(MemoryBuffer.fromByteArray(mapBytes), mapTypeRef), map);
}
}

@Test
public void testByteBufferPositionLimit() {
Fory writer =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.fory.ForyTestBase;
import org.apache.fory.exception.DeserializationException;
import org.apache.fory.memory.MemoryBuffer;
import org.apache.fory.reflect.TypeRef;
import org.apache.fory.test.bean.Foo;
import org.testng.annotations.Test;

Expand All @@ -43,9 +44,11 @@ public void testDeserializeStream() {
Foo foo = Foo.create();
BlockedStreamUtils.serialize(fory, stream, foo);
BlockedStreamUtils.serialize(fory, stream, foo);
BlockedStreamUtils.serialize(fory, stream, foo);
ByteArrayInputStream inputStream = new ByteArrayInputStream(stream.toByteArray());
assertEquals(BlockedStreamUtils.deserialize(fory, inputStream), foo);
assertEquals(BlockedStreamUtils.deserialize(fory, inputStream, Foo.class), foo);
assertEquals(BlockedStreamUtils.deserialize(fory, inputStream, new TypeRef<Foo>() {}), foo);
}

@Test
Expand All @@ -55,10 +58,12 @@ public void testDeserializeChannel() {
Foo foo = Foo.create();
BlockedStreamUtils.serialize(fory, stream, foo);
BlockedStreamUtils.serialize(fory, stream, foo);
BlockedStreamUtils.serialize(fory, stream, foo);
try (MemoryBufferReadableChannel channel =
new MemoryBufferReadableChannel(MemoryBuffer.fromByteArray(stream.toByteArray()))) {
assertEquals(BlockedStreamUtils.deserialize(fory, channel), foo);
assertEquals(BlockedStreamUtils.deserialize(fory, channel, Foo.class), foo);
assertEquals(BlockedStreamUtils.deserialize(fory, channel, new TypeRef<Foo>() {}), foo);
}
}

Expand Down
Loading