CORDA-1747 fix issue around RPC return of generic objects (#3625)

* fix issue around RPC return of generic objects

* address review comments
This commit is contained in:
Stefano Franz
2018-07-17 12:19:06 +01:00
committed by GitHub
parent a8fa232301
commit 829be5dfb6
5 changed files with 253 additions and 16 deletions

View File

@ -1,26 +1,180 @@
package net.corda.serialization.internal.amqp;
import net.corda.core.serialization.CordaSerializable;
import net.corda.core.serialization.SerializedBytes;
import net.corda.serialization.internal.amqp.custom.BigIntegerSerializer;
import net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt;
import net.corda.serialization.internal.amqp.testutils.TestSerializationContext;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;
import java.io.NotSerializableException;
import java.math.BigInteger;
import java.util.*;
import static net.corda.serialization.internal.amqp.testutils.AMQPTestUtilsKt.testDefaultFactory;
import static org.jgroups.util.Util.assertEquals;
@SuppressWarnings("unchecked")
public class JavaGenericsTest {
private static class Inner {
private final Integer v;
private Inner(Integer v) { this.v = v; }
Integer getV() { return v; }
private Inner(Integer v) {
this.v = v;
}
Integer getV() {
return v;
}
}
private static class A<T> {
private final T t;
private A(T t) { this.t = t; }
public T getT() { return t; }
private A(T t) {
this.t = t;
}
public T getT() {
return t;
}
}
@CordaSerializable
private static class ConcreteClass {
private final String theItem;
private ConcreteClass(String theItem) {
this.theItem = theItem;
}
public String getTheItem() {
return theItem;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConcreteClass that = (ConcreteClass) o;
return Objects.equals(theItem, that.theItem);
}
@Override
public int hashCode() {
return Objects.hash(theItem);
}
}
@CordaSerializable
private static class GenericClassWithList<CC> {
private final List<CC> items;
private GenericClassWithList(List<CC> items) {
this.items = items;
}
public List<CC> getItems() {
return items;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GenericClassWithList<?> that = (GenericClassWithList<?>) o;
return Objects.equals(items, that.items);
}
@Override
public int hashCode() {
return Objects.hash(items);
}
}
@CordaSerializable
private static class GenericClassWithMap<CC, GG> {
private final Map<CC, GG> theMap;
private GenericClassWithMap(Map<CC, GG> theMap) {
this.theMap = new LinkedHashMap<>(theMap);
}
public Map<CC, GG> getTheMap() {
return theMap;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GenericClassWithMap<?, ?> that = (GenericClassWithMap<?, ?>) o;
return Objects.equals(theMap, that.theMap);
}
@Override
public int hashCode() {
return Objects.hash(theMap);
}
}
@CordaSerializable
private static class HolderOfGeneric<G> {
private final G theGeneric;
private HolderOfGeneric(G theGeneric) {
this.theGeneric = theGeneric;
}
public G getTheGeneric() {
return theGeneric;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HolderOfGeneric<?> that = (HolderOfGeneric<?>) o;
return Objects.equals(theGeneric, that.theGeneric);
}
@Override
public int hashCode() {
return Objects.hash(theGeneric);
}
}
@Test
public void shouldSupportNestedGenericsFromJavaWithCollections() throws NotSerializableException {
ConcreteClass concreteClass = new ConcreteClass("How to make concrete, $99/class");
HolderOfGeneric<GenericClassWithList<ConcreteClass>> genericList = new HolderOfGeneric<>(new GenericClassWithList<>(Collections.singletonList(concreteClass)));
SerializerFactory factory = AMQPTestUtilsKt.testDefaultFactoryWithWhitelist();
SerializationOutput ser = new SerializationOutput(factory);
SerializedBytes<?> bytes = ser.serialize(genericList, TestSerializationContext.testSerializationContext);
DeserializationInput des = new DeserializationInput(factory);
HolderOfGeneric<GenericClassWithList<ConcreteClass>> genericList2 = des.deserialize(bytes, HolderOfGeneric.class, TestSerializationContext.testSerializationContext);
Assert.assertThat(genericList, CoreMatchers.is(CoreMatchers.equalTo(genericList2)));
}
@Test
public void shouldSupportNestedGenericsFromJavaWithMaps() throws NotSerializableException {
ConcreteClass concreteClass = new ConcreteClass("How to make concrete, $99/class");
GenericClassWithMap<ConcreteClass, BigInteger> genericMap = new GenericClassWithMap<>(Collections.singletonMap(concreteClass, BigInteger.ONE));
SerializerFactory factory = AMQPTestUtilsKt.testDefaultFactoryWithWhitelist();
factory.register(BigIntegerSerializer.INSTANCE);
SerializationOutput ser = new SerializationOutput(factory);
SerializedBytes<?> bytes = ser.serialize(genericMap, TestSerializationContext.testSerializationContext);
DeserializationInput des = new DeserializationInput(factory);
GenericClassWithMap<ConcreteClass, BigInteger> genericMap2 = des.deserialize(bytes, GenericClassWithMap.class, TestSerializationContext.testSerializationContext);
Assert.assertThat(genericMap2, CoreMatchers.is(CoreMatchers.equalTo(genericMap2)));
}
@Test
@ -67,7 +221,7 @@ public class JavaGenericsTest {
@Test
public void forceWildcard() throws NotSerializableException {
SerializedBytes<?> bytes = forceWildcardSerialize(new A<>(new Inner(29)));
Inner i = (Inner)forceWildcardDeserialize(bytes).getT();
Inner i = (Inner) forceWildcardDeserialize(bytes).getT();
assertEquals(29, i.getV());
}
@ -76,7 +230,7 @@ public class JavaGenericsTest {
SerializerFactory factory = testDefaultFactory();
SerializedBytes<?> bytes = forceWildcardSerializeFactory(new A<>(new Inner(29)), factory);
Inner i = (Inner)forceWildcardDeserializeFactory(bytes, factory).getT();
Inner i = (Inner) forceWildcardDeserializeFactory(bytes, factory).getT();
assertEquals(29, i.getV());
}