Skip to content

Nested container types failed to marshall/unmarshall #451

@jabolina

Description

@jabolina

We have a few container types designed to wrap collections in the types module. Upon closer inspection, the generated code for these containers has two methods:

  • T read(ReadContext ctx): which reads the context and creates the object of type T.
  • void write(WriteContext ctx, T t): which reads the object of type T and marshall into the context.

The problem is that the write method is always empty. Usually, this seems fine, but there are cases where this is a problem:

public class RangeQuery {

   private final Map<String, ArrayList<Book>> books;

   @ProtoFactory
   public RangeQuery(Map<String, ArrayList<Book>> books) {
      this.books = books;
   }

   @SuppressWarnings({"rawtypes", "unchecked"})
   @ProtoField(number = 1, mapImplementation = HashMap.class)
   public Map<String, ArrayList> getBooks() {
      return (Map<String, ArrayList>) ((Object) books);
   }

   @ProtoSchema(
         syntax = ProtoSyntax.PROTO3,
         dependsOn = {
               BookSchema.class,
               CommonContainerTypes.class,
         },
         includeClasses = RangeQuery.class,
         schemaFileName = "range-query.proto",
         schemaFilePath = "proto/",
         schemaPackageName = "queries"
   )
   public interface RangeQuerySchema extends GeneratedSchema { }
}

With test:

   @Test
   public void testRangeQuery() throws IOException {
      ArrayList<Book> books = new ArrayList<>(
            List.of(
                  new Book("Fellowship", "Tiny people and rings", 1954),
                  new Book("Towers", "Marsh with fun smell", 1954),
                  new Book("King", "Big mountain and eagles", 1955)
            )
      );

      var query = new RangeQuery(Map.of("tolkien", books));
      var bytes = ProtobufUtil.toWrappedByteArray(context, query, 512);
      System.out.println(Arrays.toString(bytes));
      var copy = ProtobufUtil.fromWrappedByteArray(context, bytes);
      System.out.println(copy);
   }

Will fail to marshall the object. It returns the following byte array:

bytes = [-126, 1, 18, 113, 117, 101, 114, 105, 101, 115, 46, 82, 97, 110, 103, 101, 81, 117, 101, 114, 121, -118, 1, 13, 10, 11, 10, 7, 116, 111, 108, 107, 105, 101, 110, 18, 0]

Which contains only the name of the type, the field number, and the "tolkien" key. Everything else inside the map is ignored because the write method in the generated container is empty.

When invoking the method to unmarshall, it will fail because the parameters for the value are interpreted as nulls because they weren't marshalled:

java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "__v$sizeParam" is null

	at org.infinispan.protostream.types.java.collections.ArrayListAdapter$___Marshaller_644b926b0d3f3b832ca16b720ed12a15fdedccbf32741bf201b2c4bb4245d40c.read(ArrayListAdapter$___Marshaller_644b926b0d3f3b832ca16b720ed12a15fdedccbf32741bf201b2c4bb4245d40c.java:38)
	at org.infinispan.protostream.types.java.collections.ArrayListAdapter$___Marshaller_644b926b0d3f3b832ca16b720ed12a15fdedccbf32741bf201b2c4bb4245d40c.read(ArrayListAdapter$___Marshaller_644b926b0d3f3b832ca16b720ed12a15fdedccbf32741bf201b2c4bb4245d40c.java:13)
	at org.infinispan.protostream.impl.ProtobufTagMarshallerDelegate.unmarshall(ProtobufTagMarshallerDelegate.java:32)
	at org.infinispan.protostream.annotations.impl.GeneratedMarshallerBase.readMessage(GeneratedMarshallerBase.java:25)
	at org.infinispan.protostream.types.java.RangeQuery$___Marshaller_dac22d3300a708d417ab87b73fde2e08e9e21c43dae8e85e158495c972f749a5.read(RangeQuery$___Marshaller_dac22d3300a708d417ab87b73fde2e08e9e21c43dae8e85e158495c972f749a5.java:54)
	at org.infinispan.protostream.types.java.RangeQuery$___Marshaller_dac22d3300a708d417ab87b73fde2e08e9e21c43dae8e85e158495c972f749a5.read(RangeQuery$___Marshaller_dac22d3300a708d417ab87b73fde2e08e9e21c43dae8e85e158495c972f749a5.java:13)
	at org.infinispan.protostream.impl.ProtobufTagMarshallerDelegate.unmarshall(ProtobufTagMarshallerDelegate.java:32)
	at org.infinispan.protostream.WrappedMessage.readCustomObject(WrappedMessage.java:588)
	at org.infinispan.protostream.WrappedMessage.readMessage(WrappedMessage.java:411)
	at org.infinispan.protostream.WrappedMessage.read(WrappedMessage.java:401)
	at org.infinispan.protostream.ProtobufUtil.fromWrappedByteArray(ProtobufUtil.java:132)
	at org.infinispan.protostream.ProtobufUtil.fromWrappedByteArray(ProtobufUtil.java:128)
	at org.infinispan.protostream.types.java.TypesMarshallingTest.testRangeQuery(TypesMarshallingTest.java:103)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runners.Suite.runChild(Suite.java:128)
	at org.junit.runners.Suite.runChild(Suite.java:27)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)

Serializing just the list with the books objects works fine. The problem seems to be with these nested containers. I also believe it needs a map in the mix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions