[JBoss JIRA] (IPROTO-56) DynamicEntity support in MarshallerProvider
by Gustavo Fernandes (JIRA)
[ https://issues.jboss.org/browse/IPROTO-56?page=com.atlassian.jira.plugin.... ]
Gustavo Fernandes updated IPROTO-56:
------------------------------------
Steps to Reproduce:
Add the test to the protostream project:
{code:java}
package org.infinispan.protostream.impl;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.protostream.BaseMarshaller;
import org.infinispan.protostream.FileDescriptorSource;
import org.infinispan.protostream.MessageMarshaller;
import org.infinispan.protostream.ProtobufUtil;
import org.infinispan.protostream.SerializationContext;
import org.infinispan.protostream.config.Configuration;
import org.infinispan.protostream.descriptors.Descriptor;
import org.infinispan.protostream.descriptors.Type;
import org.junit.Test;
public class DynamicEntityTest {
private SerializationContextImpl createContext() {
return (SerializationContextImpl) ProtobufUtil.newSerializationContext(Configuration.builder().build());
}
// Inner class, represents the properties of the Dynamic Entity
class Child<T> {
String key;
T property;
Child(String key, T property) {
this.key = key;
this.property = property;
}
}
// Dynamic entity
class DynamicEntity {
int id;
String type;
List<Child<?>> children;
DynamicEntity(int id, String type, List<Child<?>> children) {
this.id = id;
this.type = type;
this.children = children;
}
private String generateProto() {
StringBuilder proto = new StringBuilder();
AtomicInteger fieldNumber = new AtomicInteger();
proto.append("message ").append(type).append(" {\n");
proto.append("required int32 ").append("id").append("=").append(fieldNumber.incrementAndGet()).append(";\n");
proto.append("required string ").append("type").append("=").append(fieldNumber.incrementAndGet()).append(";\n");
children.forEach(c -> {
String type = c.property instanceof Integer ? "int32" : "string";
proto.append("required ").append(type).append(" ").append(c.key).append("=").append(fieldNumber.incrementAndGet()).append(";\n");
});
return proto.append(" } ").toString();
}
}
// The Marshaller for the DynamicEntity
class EntityMarshaller implements MessageMarshaller<DynamicEntity> {
private String type;
EntityMarshaller(String type) {
this.type = type;
}
@Override
public DynamicEntity readFrom(ProtoStreamReader reader) throws IOException {
Descriptor descriptor = reader.getSerializationContext().getMessageDescriptor(this.getTypeName());
int id = reader.readInt("id");
String type = reader.readString("type");
List<Child<?>> children = descriptor.getFields().stream()
.filter(fd -> !fd.getName().equals("id") && !fd.getName().equals("type"))
.map(field -> {
try {
String name = field.getName();
Object value;
if (field.getType() == Type.INT32) {
value = reader.readInt(name);
} else {
value = reader.readString(name);
}
return new Child<>(field.getName(), value);
} catch (Exception ignored) {
return null;
}
})
.collect(toList());
return new DynamicEntity(id, type, children);
}
@Override
public void writeTo(ProtoStreamWriter writer, DynamicEntity topLevel) throws IOException {
writer.writeInt("id", topLevel.id);
writer.writeString("type", topLevel.type);
topLevel.children.forEach(c -> {
try {
String name = c.key;
Object value = c.property;
if (value instanceof Integer) {
writer.writeInt(name, (Integer) value);
} else {
writer.writeString(name, value.toString());
}
} catch (Exception ignored) {
}
});
}
@Override
public Class<? extends DynamicEntity> getJavaClass() {
return DynamicEntity.class;
}
@Override
public String getTypeName() {
return type;
}
}
@Test
public void testMarshallerProviderDynamicTypes() throws IOException {
// Create two dynamic types
DynamicEntity dynamicEntity = new DynamicEntity(1, "type1",
asList(new Child<>("eyes", "blue"), new Child<>("age", 23)));
DynamicEntity otherDynamicEntity = new DynamicEntity(2, "type2",
asList(new Child<>("country", "Jamaica"), new Child<>("currency", "jmd")));
// Auto generate the proto file from the entities and register them
SerializationContextImpl ctx = createContext();
String protoFile1 = dynamicEntity.generateProto();
String protoFile2 = otherDynamicEntity.generateProto();
System.out.println(protoFile1);
System.out.println(protoFile2);
ctx.registerProtoFiles(new FileDescriptorSource()
.addProtoFile(dynamicEntity.type + ".proto", protoFile1)
.addProtoFile(otherDynamicEntity.type + ".proto", protoFile2));
// Register a marshaller provider
ctx.registerMarshallerProvider(new SerializationContext.MarshallerProvider() {
@Override
public BaseMarshaller<?> getMarshaller(String typeName) {
return new EntityMarshaller(typeName);
}
@Override
public BaseMarshaller<?> getMarshaller(Class<?> javaClass) {
// HARDCODED, ideally it should be able to expose to obtain the 'type' from the class
return new EntityMarshaller("type1");
}
});
byte[] bytes = ProtobufUtil.toByteArray(ctx, dynamicEntity);
DynamicEntity input = ProtobufUtil.fromByteArray(ctx, bytes, DynamicEntity.class);
assertEquals(1, input.id);
assertEquals("type1", input.type);
assertEquals(2, input.children.size());
Child<?> first = input.children.get(0);
assertEquals("eyes", first.key);
assertEquals("blue", first.property);
Child<?> second = input.children.get(1);
assertEquals("age", second.key);
assertEquals(23, second.property);
// Does not work with other types...
// byte[] anotherBytes = ProtobufUtil.toByteArray(ctx, otherDynamicEntity);
// DynamicEntity anotherInput = ProtobufUtil.fromByteArray(ctx, bytes, DynamicEntity.class);
}
}
{code}
was:
Add the test to the protostream project:
{code:java}
package org.infinispan.protostream.impl;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.infinispan.protostream.BaseMarshaller;
import org.infinispan.protostream.FileDescriptorSource;
import org.infinispan.protostream.MessageMarshaller;
import org.infinispan.protostream.ProtobufUtil;
import org.infinispan.protostream.SerializationContext;
import org.infinispan.protostream.config.Configuration;
import org.infinispan.protostream.descriptors.Descriptor;
import org.infinispan.protostream.descriptors.Type;
import org.junit.Test;
public class DynamicEntityTest {
private SerializationContextImpl createContext() {
return (SerializationContextImpl) ProtobufUtil.newSerializationContext(Configuration.builder().build());
}
// Inner class, represents the properties of the Dynamic Entity
class Child<T> {
String key;
T property;
Child(String key, T property) {
this.key = key;
this.property = property;
}
}
// Dynamic entity
class DynamicEntity {
int id;
String type;
List<Child<?>> children;
DynamicEntity(int id, String type, List<Child<?>> children) {
this.id = id;
this.type = type;
this.children = children;
}
private String generateProto() {
StringBuilder proto = new StringBuilder();
AtomicInteger fieldNumber = new AtomicInteger();
proto.append("message ").append(type).append(" {\n");
proto.append("required int32 ").append("id").append("=").append(fieldNumber.incrementAndGet()).append(";\n");
proto.append("required string ").append("type").append("=").append(fieldNumber.incrementAndGet()).append(";\n");
children.forEach(c -> {
String type = c.property instanceof Integer ? "int32" : "string";
proto.append("required ").append(type).append(" ").append(c.key).append("=").append(fieldNumber.incrementAndGet()).append(";\n");
});
return proto.append(" } ").toString();
}
}
// The Marshaller for the DynamicEntity
class EntityMarshaller implements MessageMarshaller<DynamicEntity> {
private String type;
EntityMarshaller(String type) {
this.type = type;
}
@Override
public DynamicEntity readFrom(ProtoStreamReader reader) throws IOException {
Descriptor descriptor = reader.getSerializationContext().getMessageDescriptor(this.getTypeName());
int id = reader.readInt("id");
String type = reader.readString("type");
List<Child<?>> children = descriptor.getFields().stream()
.filter(fd -> !fd.getName().equals("id") && !fd.getName().equals("type"))
.map(field -> {
try {
String name = field.getName();
Object value;
if (field.getType() == Type.INT32) {
value = reader.readInt(name);
} else {
value = reader.readString(name);
}
return new Child<>(field.getName(), value);
} catch (Exception ignored) {
return null;
}
})
.collect(toList());
return new DynamicEntity(id, type, children);
}
@Override
public void writeTo(ProtoStreamWriter writer, DynamicEntity topLevel) throws IOException {
writer.writeInt("id", topLevel.id);
writer.writeString("type", topLevel.type);
topLevel.children.forEach(c -> {
try {
String name = c.key;
Object value = c.property;
if (value instanceof Integer) {
writer.writeInt(name, (Integer) value);
} else {
writer.writeString(name, value.toString());
}
} catch (Exception ignored) {
}
});
}
@Override
public Class<? extends DynamicEntity> getJavaClass() {
return DynamicEntity.class;
}
@Override
public String getTypeName() {
return type;
}
}
@Test
public void testMarshallerProviderDynamicTypes() throws IOException {
// Create two dynamic types
DynamicEntity dynamicEntity = new DynamicEntity(1, "type1",
asList(new Child<>("eyes", "blue"), new Child<>("age", 23)));
DynamicEntity otherDynamicEntity = new DynamicEntity(2, "type2",
asList(new Child<>("country", "Jamaica"), new Child<>("currency", "jmd")));
// Auto generate the proto file from the entities and register them
SerializationContextImpl ctx = createContext();
String protoFile1 = dynamicEntity.generateProto();
String protoFile2 = otherDynamicEntity.generateProto();
System.out.println(protoFile1);
System.out.println(protoFile2);
ctx.registerProtoFiles(new FileDescriptorSource()
.addProtoFile(dynamicEntity.type + ".proto", protoFile1)
.addProtoFile(otherDynamicEntity.type + ".proto", protoFile2));
// Register a marshaller provider
ctx.registerMarshallerProvider(new SerializationContext.MarshallerProvider() {
@Override
public BaseMarshaller<?> getMarshaller(String typeName) {
return new EntityMarshaller(typeName);
}
@Override
public BaseMarshaller<?> getMarshaller(Class<?> javaClass) {
// HARDCODED, ideally it should be able to expose to obtain the 'type' from the class
return new EntityMarshaller("type1");
}
});
byte[] bytes = ProtobufUtil.toByteArray(ctx, dynamicEntity);
DynamicEntity input = ProtobufUtil.fromByteArray(ctx, bytes, DynamicEntity.class);
assertEquals(1, input.id);
assertEquals("type1", input.type);
assertEquals(2, input.children.size());
Child<?> first = input.children.get(0);
assertEquals("eyes", first.key);
assertEquals("blue", first.property);
Child<?> second = input.children.get(1);
assertEquals("eyes", first.key);
assertEquals("blue", first.property);
// Does not work with other types...
// byte[] anotherBytes = ProtobufUtil.toByteArray(ctx, otherDynamicEntity);
// DynamicEntity anotherInput = ProtobufUtil.fromByteArray(ctx, bytes, DynamicEntity.class);
}
}
{code}
> DynamicEntity support in MarshallerProvider
> -------------------------------------------
>
> Key: IPROTO-56
> URL: https://issues.jboss.org/browse/IPROTO-56
> Project: Infinispan ProtoStream
> Issue Type: Bug
> Reporter: Gustavo Fernandes
>
> The use case is a class that describe the entity. This class contains a 'type' and a list of properties. MarshallerProvider is used to associate a type with a marshaller that uses this 'type' to understand the fields and data types to read/write the stream.
> The type of the entity is contained in the entity itself, and when reading from the stream, this type is used to figure out the fields to read. During writes, though, the type is not involved so it's not possible to use the same strategy.
> Attached is a unit test to illustrate the situation. This is not necessarily a bug, it may be possible to achieve the usage of Dynamic Entities under other circumstances, or maybe the API needs to be extended.
--
This message was sent by Atlassian JIRA
(v7.5.0#75005)
6 years, 6 months
[JBoss JIRA] (IPROTO-56) DynamicEntity support in MarshallerProvider
by Gustavo Fernandes (JIRA)
[ https://issues.jboss.org/browse/IPROTO-56?page=com.atlassian.jira.plugin.... ]
Gustavo Fernandes updated IPROTO-56:
------------------------------------
Description:
The use case is a class that describe the entity. This class contains a 'type' and a list of properties. MarshallerProvider is used to associate a type with a marshaller that uses this 'type' to understand the fields and data types to read/write the stream.
The type of the entity is contained in the entity itself, and when reading from the stream, this type is used to figure out the fields to read. During writes, though, the type is not involved so it's not possible to use the same strategy.
Attached is a unit test to illustrate the situation. This is not necessarily a bug, it may be possible to achieve the usage of Dynamic Entities under other circumstances, or maybe the API needs to be extended.
was:
The use case is there is a class that describe the entity, which contains a 'type' and a list of properties. MarshallerProvider is used to associate a type with a marshaller that uses that 'type' to read/write
The type of entity is contained in the entity itself, and when reading from the stream, this type is used to figure out the fields to read. During writes, though, the type is not involved so it's not possible to use the same strategy.
Attached is a unit test to illustrate the situation. This is not necessarily a bug, it may be possible to achieve the usage of Dynamic Entities under other circumstances, or maybe the API needs to be extended.
> DynamicEntity support in MarshallerProvider
> -------------------------------------------
>
> Key: IPROTO-56
> URL: https://issues.jboss.org/browse/IPROTO-56
> Project: Infinispan ProtoStream
> Issue Type: Bug
> Reporter: Gustavo Fernandes
>
> The use case is a class that describe the entity. This class contains a 'type' and a list of properties. MarshallerProvider is used to associate a type with a marshaller that uses this 'type' to understand the fields and data types to read/write the stream.
> The type of the entity is contained in the entity itself, and when reading from the stream, this type is used to figure out the fields to read. During writes, though, the type is not involved so it's not possible to use the same strategy.
> Attached is a unit test to illustrate the situation. This is not necessarily a bug, it may be possible to achieve the usage of Dynamic Entities under other circumstances, or maybe the API needs to be extended.
--
This message was sent by Atlassian JIRA
(v7.5.0#75005)
6 years, 6 months
[JBoss JIRA] (IPROTO-56) DynamicEntity support in MarshallerProvider
by Gustavo Fernandes (JIRA)
Gustavo Fernandes created IPROTO-56:
---------------------------------------
Summary: DynamicEntity support in MarshallerProvider
Key: IPROTO-56
URL: https://issues.jboss.org/browse/IPROTO-56
Project: Infinispan ProtoStream
Issue Type: Bug
Reporter: Gustavo Fernandes
The use case is there is a class that describe the entity, which contains a 'type' and a list of properties. MarshallerProvider is used to associate a type with a marshaller that uses that 'type' to read/write
The type of entity is contained in the entity itself, and when reading from the stream, this type is used to figure out the fields to read. During writes, though, the type is not involved so it's not possible to use the same strategy.
Attached is a unit test to illustrate the situation. This is not necessarily a bug, it may be possible to achieve the usage of Dynamic Entities under other circumstances, or maybe the API needs to be extended.
--
This message was sent by Atlassian JIRA
(v7.5.0#75005)
6 years, 6 months
[JBoss JIRA] (ISPN-8431) ScatteredSplitAndMergeTest random failures
by Radim Vansa (JIRA)
[ https://issues.jboss.org/browse/ISPN-8431?page=com.atlassian.jira.plugin.... ]
Radim Vansa updated ISPN-8431:
------------------------------
Status: Pull Request Sent (was: Open)
Git Pull Request: https://github.com/infinispan/infinispan/pull/6073
> ScatteredSplitAndMergeTest random failures
> ------------------------------------------
>
> Key: ISPN-8431
> URL: https://issues.jboss.org/browse/ISPN-8431
> Project: Infinispan
> Issue Type: Bug
> Components: Test Suite - Core
> Affects Versions: 9.2.0.Alpha1
> Environment: Jenkins
> Reporter: Tristan Tarrant
> Assignee: Radim Vansa
> Labels: testsuite_stability
> Fix For: 9.3.0.Final
>
> Attachments: ScatteredSplitAndMergeTest_20180129.log.gz, ScatteredSplitAndMergeTest_ISPN-7919_RpcManager_ResponseCollector_20171212.log.gz
>
>
> http://ci.infinispan.org/job/Infinispan/job/master/214/testReport/junit/o...
> java.lang.AssertionError: expected [null] but found [v0]
> at org.infinispan.partitionhandling.ScatteredSplitAndMergeTest.testSplitAndMerge(ScatteredSplitAndMergeTest.java:80)
> at org.infinispan.partitionhandling.ScatteredSplitAndMergeTest.testSplitAndMerge5(ScatteredSplitAndMergeTest.java:51)
> at java.util.concurrent.FutureTask.run(FutureTask.java:266)
> at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
> at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
> at java.lang.Thread.run(Thread.java:748)
> ... Removed 20 stack frames
>
--
This message was sent by Atlassian JIRA
(v7.5.0#75005)
6 years, 6 months
[JBoss JIRA] (ISPN-8431) ScatteredSplitAndMergeTest random failures
by Radim Vansa (JIRA)
[ https://issues.jboss.org/browse/ISPN-8431?page=com.atlassian.jira.plugin.... ]
Radim Vansa updated ISPN-8431:
------------------------------
Fix Version/s: 9.3.0.Final
> ScatteredSplitAndMergeTest random failures
> ------------------------------------------
>
> Key: ISPN-8431
> URL: https://issues.jboss.org/browse/ISPN-8431
> Project: Infinispan
> Issue Type: Bug
> Components: Test Suite - Core
> Affects Versions: 9.2.0.Alpha1
> Environment: Jenkins
> Reporter: Tristan Tarrant
> Assignee: Radim Vansa
> Labels: testsuite_stability
> Fix For: 9.3.0.Final
>
> Attachments: ScatteredSplitAndMergeTest_20180129.log.gz, ScatteredSplitAndMergeTest_ISPN-7919_RpcManager_ResponseCollector_20171212.log.gz
>
>
> http://ci.infinispan.org/job/Infinispan/job/master/214/testReport/junit/o...
> java.lang.AssertionError: expected [null] but found [v0]
> at org.infinispan.partitionhandling.ScatteredSplitAndMergeTest.testSplitAndMerge(ScatteredSplitAndMergeTest.java:80)
> at org.infinispan.partitionhandling.ScatteredSplitAndMergeTest.testSplitAndMerge5(ScatteredSplitAndMergeTest.java:51)
> at java.util.concurrent.FutureTask.run(FutureTask.java:266)
> at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
> at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
> at java.lang.Thread.run(Thread.java:748)
> ... Removed 20 stack frames
>
--
This message was sent by Atlassian JIRA
(v7.5.0#75005)
6 years, 6 months