Skip to content

[Avro] JsonMappingException for union types with multiple Record types #168

Closed
@amorimjuliana

Description

@amorimjuliana

I believe this is a different issue from #123 and #164.

In the following example, we have a union schema with 5 record schemas and an abstract class annotated with @Union as follows:

@Union({
    ClassA.class,
    ClassB.class,
    ClassC.class,
    ClassD.class,
    ClassE.class
})
abstract class AbstractClass {
    public static final Schema SCHEMA = Schema.createUnion(
        ClassA.SCHEMA,
        ClassB.SCHEMA,
        ClassC.SCHEMA,
        ClassD.SCHEMA,
        ClassE.SCHEMA
    );
}

class ClassA extends AbstractClass {}
class ClassB extends AbstractClass {}
class ClassC extends AbstractClass {}
class ClassD extends AbstractClass {}
class ClassE extends AbstractClass {}

Problem 1: serialize as a concrete class and deserialize as an abstract class

final byte[] bytes = avroMapper
    .writer(new AvroSchema(ClassA.SCHEMA))
    .writeValueAsBytes(new ClassA());

final ClassA result = avroMapper
    .readerFor(AbstractClasss.class)
    .with(new AvroSchema(AbstractClass.SCHEMA))
    .readValue(bytes); // Error

When we serialize a value using the concrete class ClassA and then try to deserialize it as the AbstractClass, we get the following error:

com.fasterxml.jackson.core.JsonParseException: Invalid index (36); union only has 5 types

	at com.fasterxml.jackson.dataformat.avro.deser.UnionReader._decodeIndex(UnionReader.java:66)
	at com.fasterxml.jackson.dataformat.avro.deser.UnionReader.nextToken(UnionReader.java:36)
	at com.fasterxml.jackson.dataformat.avro.deser.RootReader.nextToken(RootReader.java:31)
	at com.fasterxml.jackson.dataformat.avro.deser.AvroParserImpl.nextToken(AvroParserImpl.java:98)
	at com.fasterxml.jackson.databind.ObjectReader._initForReading(ObjectReader.java:355)
	at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1596)
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1234)

Although serializing and then deserializing the class using the concrete class ClassA works.

Problem 2: serialize as an abstract class

final byte[] bytes = avroMapper
    .writer(new AvroSchema(AbstractClasss.SCHEMA))
    .writeValueAsBytes(new ClassA()); // Error

Also, the serialization using the abstract class AbstractClass does not work:

com.fasterxml.jackson.databind.JsonMappingException: Multiple Record and/or Map types, can not figure out which to use for: [{"x":"y"}]

	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._wrapAsIOE(DefaultSerializerProvider.java:509)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:482)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1396)
	at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1120)
	at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsBytes(ObjectWriter.java:1017)

I believe that both cases are valid and should not cause errors, or maybe I'm missing something.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions