我想创建一个如下所示的公共dto,用于从REST服务接收传入的Manager和Staff详细信息
public class Employee {
@JsonProperty("name")
public String name;
@JsonProperty("designation")
public String designation;
@JsonProperty("item")
public String item;
@JsonProperty("item")
public List<Item> items;
//setters and getters
}
问题是对于for Manager,item字段将是一个List,其中Staff将是一个字符串,所以我为item创建了两个字段,一个用于接收String而另一个用于List,但它不起作用,我得到了Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
。
传入的json详细信息如下所示
经理传入的json
{
"name": "Rohit",
"designation": "Manager",
"item": {"name": "ABC", "desc": "1234"}
}
工作人员传入json
{
"name": "Manu",
"designation": "Staff",
"item": "abc"
}
任何人都可以告诉我一些解决方案吗
答案 0 :(得分:1)
您可以创建客户反序列化程序。如果"item"
字段的节点是数组,则将其反序列化为数组,否则将其反序列化为String。例如
public static class EmployeeDeserializer extends JsonDeserializer<Employee> {
@Override
public Employee deserialize(JsonParser jp,
DeserializationContext dc)
throws IOException, JsonProcessingException {
Employee emp = new Employee();
JsonNode root = jp.getCodec().readTree(jp);
emp.name = root.get("name").asText();
emp.designation = root.get("designation").asText();
JsonNode itemNode = root.get("item");
if (itemNode.isArray()) {
ArrayNode itemsNode = (ArrayNode) itemNode;
List<Item> items = new ArrayList<>();
for (JsonNode iNode : itemsNode) {
Item item = new Item();
item.name = iNode.get("name").asText();
item.desc = iNode.get("desc").asText();
items.add(item);
}
emp.items = items;
} else if (itemNode.isObject()) {
List<Item> items = new ArrayList<>();
Item item = new Item();
item.name = itemNode.get("name").asText();
item.desc = itemNode.get("desc").asText();
items.add(item);
emp.items = items;
} else {
String item = root.get("item").asText();
emp.item = item;
}
return emp;
}
}
我实际上为"item"
添加了三个案例。它可以是一个JSON数组作为多个Items,一个JSON对象(这是你在帖子中所拥有的)作为单个Item,或者是一个字符串供员工使用。如果它是JSON对象,我只需创建单个Item
并将其添加到List
这是一个完整的测试
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
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.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
public class EmployeeTest {
@JsonDeserialize(using = EmployeeDeserializer.class)
public static class Employee {
public String name;
public String designation;
public String item;
public List<Item> items;
}
public static class Item {
public String name;
public String desc;
@Override
public String toString() {
return "Item{" + "name=" + name + ", desc=" + desc + '}';
}
}
public static class EmployeeDeserializer extends JsonDeserializer<Employee> {
@Override
public Employee deserialize(JsonParser jp,
DeserializationContext dc)
throws IOException, JsonProcessingException {
Employee emp = new Employee();
JsonNode root = jp.getCodec().readTree(jp);
emp.name = root.get("name").asText();
emp.designation = root.get("designation").asText();
JsonNode itemNode = root.get("item");
if (itemNode.isArray()) {
ArrayNode itemsNode = (ArrayNode) itemNode;
List<Item> items = new ArrayList<>();
for (JsonNode iNode : itemsNode) {
Item item = new Item();
item.name = iNode.get("name").asText();
item.desc = iNode.get("desc").asText();
items.add(item);
}
emp.items = items;
} else if (itemNode.isObject()) {
List<Item> items = new ArrayList<>();
Item item = new Item();
item.name = itemNode.get("name").asText();
item.desc = itemNode.get("desc").asText();
items.add(item);
emp.items = items;
} else {
String item = root.get("item").asText();
emp.item = item;
}
return emp;
}
}
private static ObjectMapper mapper;
@BeforeClass
public static void setUpMapper() {
mapper = new ObjectMapper();
//SimpleModule module = new SimpleModule();
//module.addDeserializer(Employee.class, new EmployeeDeserializer());
//mapper.registerModule(module);
}
@Test
public void should_deserialize_manager_list_ok() throws Exception {
final String mgrJson
= "{\n"
+ " \"name\": \"Rohit\",\n"
+ " \"designation\": \"Manager\",\n"
+ " \"item\": [{\"name\": \"ABC\", \"desc\": \"1234\"}]\n"
+ "}";
Employee mgr = mapper.readValue(mgrJson, Employee.class);
assertEquals("Rohit", mgr.name);
assertEquals("Manager", mgr.designation);
assertNull(mgr.item);
assertEquals(1, mgr.items.size());
assertEquals("ABC", mgr.items.get(0).name);
assertEquals("1234", mgr.items.get(0).desc);
}
@Test
public void should_deserialize_staff_string_ok() throws Exception {
final String staffJson
= "{\n"
+ " \"name\": \"Manu\",\n"
+ " \"designation\": \"Staff\",\n"
+ " \"item\": \"abc\"\n"
+ "}";
Employee staff = mapper.readValue(staffJson, Employee.class);
assertEquals("Manu", staff.name);
assertEquals("Staff", staff.designation);
assertEquals("abc", staff.item);
assertNull(staff.items);
}
@Test
public void should_deserialize_single_item_ok() throws Exception {
final String mgrJson
= "{\n"
+ " \"name\": \"Rohit\",\n"
+ " \"designation\": \"Manager\",\n"
+ " \"item\": {\"name\": \"ABC\", \"desc\": \"1234\"}\n"
+ "}";
Employee mgr = mapper.readValue(mgrJson, Employee.class);
assertEquals("Rohit", mgr.name);
assertEquals("Manager", mgr.designation);
assertNull(mgr.item);
assertEquals(1, mgr.items.size());
assertEquals("ABC", mgr.items.get(0).name);
assertEquals("1234", mgr.items.get(0).desc);
}
}
答案 1 :(得分:1)
您可以让Manager和Staff扩展一个抽象类Employee,然后使用'designation'JSON属性来区分它们:
// note hashCode(), equals() and toString() methods left out for brevity!
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "designation")
@JsonSubTypes({ @JsonSubTypes.Type(Staff.class), @JsonSubTypes.Type(Manager.class) })
public static abstract class Employee {
@JsonProperty("name")
public String name;
public Employee(String name) {
this.name = name;
}
public Employee() {
}
}
@JsonTypeName("Manager")
public static final class Manager extends Employee {
@JsonProperty("item")
public List<Item> items;
public Manager(String name, List<Item> items) {
super(name);
this.items = items;
}
public Manager() {
}
public static final class Item {
public final String name;
public final String desc;
public Item(@JsonProperty("name") String name, @JsonProperty("desc") String desc) {
this.name = name;
this.desc = desc;
}
}
}
@JsonTypeName("Staff")
public static final class Staff extends Employee {
@JsonProperty("item")
public String item;
public Staff(String name) {
super(name);
this.item = item;
}
public Staff() {
}
}
试验:
@Test
public void polymorphic_deserialization_of_manager() throws Exception {
ObjectMapper mapper = new ObjectMapper().enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES)
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
.enable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
String json = "{ name: 'Rohit', designation: 'Manager', item: { name: 'ABC', desc: '1234' } }";
Employee employee = new Manager("Rohit", ImmutableList.of(new Manager.Item("ABC", "1234")));
assertThat(mapper.readValue(json, Employee.class), equalTo(employee));
assertThat(mapper.writeValueAsString(employee), equivalentTo(json));
}
@Test
public void polymorphic_deserialization_of_staff() throws Exception {
ObjectMapper mapper = new ObjectMapper().enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES).enable(
JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
String json = "{ name: 'Manu', designation: 'Staff', item: 'abc' }";
Employee employee = new Staff("Manu", "abc");
assertThat(mapper.readValue(json, Employee.class), equalTo(employee));
assertThat(mapper.writeValueAsString(employee), equivalentTo(json));
}