簡體   English   中英

兩個傳入 REST json 的公共 dto

[英]common dto for two incoming REST json

我想創建一個如下所示的通用 dto,用於從 REST 服務接收傳入的經理和員工詳細信息

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
}

問題是對於經理,項目字段將是一個列表,而對於員工,它將是一個字符串,所以我為項目創建了兩個字段,一個用於接收字符串,另一個用於列表,但它不起作用,我得到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"
}

誰能告訴我一些解決方案

您可以創建一個客戶解串器。 如果"item"字段的節點是數組,則將其反序列化為數組,否則將其反序列化為字符串。 例如

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 數組,作為單個項目的 JSON 對象(這是您在帖子中擁有的),或者是工作人員的字符串。 如果是 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);
    }
}

你可以讓 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));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM