Es gibt eine API, die JSON mit Eigenschaften des Objekttyps zurückgibt, wenn ein Wert vorhanden ist, und einen Array-Typ, wenn dieser leer ist. Standardmäßig stimmen die Typen nicht überein und können nicht an die Klasse gebunden werden.
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `net.yotama.sample.resource.Resource$Member` out of START_ARRAY token
at [Source: (String)"{"member": []}"; line: 1, column: 12](through reference chain: net.yotama.sample.resource.Resource["member"])
Verwenden Sie Jacksons JsonDeserializer
und ersetzen Sie ihn durch null, wenn es sich um ein Array handelt, damit es an eine Ressourcenklasse gebunden werden kann.
Wenn es einen Wert gibt
{
"member": {
"name": "yotama"
}
}
Wenn es keinen Wert gibt
{
"member": []
}
Resource.java
package net.yotama.sample.resource;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Value;
import java.io.IOException;
@Value
public class Resource {
@JsonDeserialize(using = MemberDeserializer.class)
Member member;
@Value
public static class Member {
String name;
}
public static class MemberDeserializer extends JsonDeserializer<Member> {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public Member deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
TreeNode treeNode = p.getCodec().readTree(p);
return treeNode.isObject() ? objectMapper.readValue(treeNode.toString(), Member.class) : null;
}
}
}
lombok.config
#Ich benutze Lombok der Einfachheit halber,
# 1.16.Verwendet von Jackson ab 20@ConstructorProperties werden nicht zugewiesen. Legen Sie sie daher vorläufig fest
lombok.anyConstructor.addConstructorProperties=true
package net.yotama.sample.resource;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import java.io.IOException;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
@RunWith(Theories.class)
public class ResourceTest {
private ObjectMapper objectMapper = new ObjectMapper();
@DataPoints
public static Fixture[] data = {
new Fixture("{\"member\": []}", new Resource(null)),
new Fixture("{\"member\": null}", new Resource(null)),
new Fixture("{\"member\": {\"name\": \"hoge\"}}", new Resource(new Resource.Member("hoge"))),
};
@Theory
public void test(Fixture fixture) throws IOException {
assertThat(objectMapper.readValue(fixture.json, Resource.class), is(fixture.expected));
}
@RequiredArgsConstructor
public static class Fixture {
final String json;
final Resource expected;
}
}
Recommended Posts