Skip to content

jClass annotations and polymorphic types are ignored when deserializing Android Record fields #248

@HelloOO7

Description

@HelloOO7

Suppose a class hierarchy like this:

public record Record(Field field) {
}

@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="@class")
@JsonSubTypes({
        @JsonSubTypes.Type(value = StringField.class, name = "string"),
        @JsonSubTypes.Type(value = IntField.class, name = "int")
})
public abstract class Field {
}

public class StringField extends Field {

	private final String val;

	@JsonCreator
	public StringField(@JsonProperty("val") String val) {
		this.val = val;
	}

	public String getVal() {
		return val;
	}
}

public class IntField extends Field {

	private final int val;

	@JsonCreator
	public IntField(@JsonProperty("val") int val) {
		this.val = val;
	}

	public int getVal() {
		return val;
	}
}

Using Jackson on standard desktop Java SE, the following code works as expected:

String serialized = new ObjectMapper().writeValueAsString(r);
new ObjectMapper().readValue(serialized, Record.class);

However, that is not the case on Android (using the AndroidRecordModule), where the deserializer is oblivious of all class annotations (and, consequently, the JsonTypeInfo), and thus is unable to deserialize the abstract type Field. (abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information)

I would presume that the issue lies within this code:

null, null, parameter.getAllAnnotations(), parameter, i, injectable, null);
since in this case, neither the TypeDeserializer, nor getClassAnnotations are used for Field.

My current workaround is to wrap objects akin to Field in this example into the following:

public class ContainerObject<T> { //Android Studio's opinion of this code is "Class can be converted to record class". Well, if only I could:)
    public final T value;

    @JsonCreator
    public ContainerObject(@JsonProperty("value") T value) {
        this.value = value;
    }
}

and then change Record to be

public record Record(ContainerObject<Field> field) {
}

Using this wrapper, deserialization works as expected on Android. However, the general issue seems to be a bug within Jackson's AndroidRecordModule.

If so desired, I'm willing to fix this myself and PR it.

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