Skip to content

Commit

Permalink
android-record: Support deserializing polymorphic members of records (f…
Browse files Browse the repository at this point in the history
…ixes #248).
  • Loading branch information
HelloOO7 committed Jul 26, 2024
1 parent 9b2fe00 commit 700ddaf
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.fasterxml.jackson.module.androidrecord;

import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.CreatorProperty;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;

public class AndroidRecordInstantiator extends StdValueInstantiator {
protected AndroidRecordInstantiator(StdValueInstantiator src) {
super(src);
}

public ValueInstantiator createContextual(DeserializationContext ctxt, BeanDescription beanDesc) throws JsonMappingException {
boolean wasChanged = false;
SettableBeanProperty[] newCtorArgs = new SettableBeanProperty[_constructorArguments.length];
for (int i = 0; i < _constructorArguments.length; i++) {
SettableBeanProperty prop = _constructorArguments[i];
if (!prop.hasValueTypeDeserializer()) {
TypeDeserializer typeDeserializer = ctxt.getFactory().findTypeDeserializer(ctxt.getConfig(), prop.getType());
if (typeDeserializer != null) {
prop = CreatorProperty.construct(
prop.getFullName(),
prop.getType(),
prop.getWrapperName(),
typeDeserializer,
prop.getMember().getAllAnnotations(),
(AnnotatedParameter) prop.getMember(),
prop.getCreatorIndex(),
ctxt.getAnnotationIntrospector().findInjectableValue(prop.getMember()),
prop.getMetadata()
);
wasChanged = true;
}
}
newCtorArgs[i] = prop;
}


if (wasChanged) {
AndroidRecordInstantiator newInstantiator = new AndroidRecordInstantiator(this);
newInstantiator._constructorArguments = newCtorArgs;
return newInstantiator;
} else {
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,13 @@ && isDesugaredRecordClass(raw)) {
null, null, parameter.getAllAnnotations(), parameter, i, injectable, null);
}

((StdValueInstantiator) defaultInstantiator).configureFromObjectSettings(null, null, null, null,
constructor, properties);
AndroidRecordInstantiator instantiator = new AndroidRecordInstantiator((StdValueInstantiator) defaultInstantiator);
instantiator.configureFromObjectSettings(null, null, null, null, constructor, properties);

ClassUtil.checkAndFixAccess(constructor.getAnnotated(), false);
found = true;

defaultInstantiator = instantiator;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.fasterxml.jackson.module.androidrecord;

import com.android.tools.r8.RecordTag;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AbstractRecordMemberTest extends BaseMapTest {

static final class RootRecord extends RecordTag {

private final AbstractMember member;

public RootRecord(AbstractMember member) {
this.member = member;
}

public AbstractMember member() {
return member;
}
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "@class")
@JsonSubTypes({
@JsonSubTypes.Type(value = StringMember.class, name = "string"),
@JsonSubTypes.Type(value = IntMember.class, name = "int")
})
static abstract class AbstractMember {
}

static final class StringMember extends AbstractMember {

private final String val;

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

public String getVal() {
return val;
}
}

static final class IntMember extends AbstractMember {

private final int val;

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

public int getVal() {
return val;
}
}

private final ObjectMapper MAPPER = newJsonMapper();

/*
/**********************************************************************
/* https://github.com/FasterXML/jackson-modules-base/issues/248
/**********************************************************************
*/
public void testDeserializeRecordWithAbstractMember() throws Exception {
RootRecord value = MAPPER.readValue("{\"member\":{\"@class\":\"string\",\"val\":\"Hello, abstract member!\"}}",
RootRecord.class);
assertNotNull(value.member());
assertEquals(StringMember.class, value.member().getClass());
assertEquals("Hello, abstract member!", ((StringMember)value.member()).getVal());
}
}

0 comments on commit 700ddaf

Please sign in to comment.