-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Milestone
Description
I have a minimal repro below. testConverter fails with a class cast. The converter is called once on JsonNode and returns a SubClass. Then it is called again with that returned SubClass and fails.
testConverter2 passes.
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.util.StdConverter;
import java.util.Collections;
import org.junit.Assert;
import org.junit.Test;
public class JacksonConverterTest {
@JsonSubTypes({
@JsonSubTypes.Type(SubClass.class),
})
@JsonTypeInfo(use = Id.NAME, include = As.EXISTING_PROPERTY, property = "type", visible = false)
interface Base {
String getType();
}
@JsonTypeName("sub")
@JsonSerialize(as = ImmutableSubClass.class)
@JsonDeserialize(as = ImmutableSubClass.class)
interface SubClass extends Base {
@Override
default String getType() {
return "sub";
}
default boolean getVisible() {
return true;
}
}
static class ImmutableSubClass implements SubClass {
public boolean visible = true;
@Override
public int hashCode() {
return visible ? 0 : 1;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ImmutableSubClass other = (ImmutableSubClass) obj;
if (visible != other.visible)
return false;
return true;
}
}
@Test
public void testConverter() throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
json.put("hidden", false);
json.put("type", "sub");
mapper.setMixIns(Collections.singletonMap(SubClass.class, SubClassMixin.class));
SubClass value = mapper.treeToValue(json, SubClass.class);
Assert.assertEquals(new ImmutableSubClass(), value);
}
@Test
public void testConverter2() throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectNode json = new ObjectNode(JsonNodeFactory.instance);
json.put("hidden", false);
json.put("type", "sub");
mapper.setMixIns(Collections.singletonMap(SubClass.class, SubClassMixin.class));
Base value = mapper.treeToValue(json, Base.class);
Assert.assertEquals(new ImmutableSubClass(), value);
}
@JsonDeserialize(converter = SubClassConverter.class)
interface SubClassMixin {}
static class SubClassConverter extends StdConverter<JsonNode, SubClass> {
@Override
public SubClass convert(JsonNode value) {
// Modify the old Json in some way that the new library will accept.
ObjectNode node = (ObjectNode) value;
boolean hidden = node.remove("hidden").asBoolean(false);
node.put("visible", !hidden);
node.put("type", "sub");
try {
return new ObjectMapper().treeToValue(node, SubClass.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
}
Metadata
Metadata
Assignees
Labels
No labels