将两个类似的json字段编组到同一个java字段

时间:2017-05-21 08:27:57

标签: java json jackson

我有一个示例虚拟JSON响应,如下所示:

    {
        "id": 1,
        "teacher_name": "Foo",
        "teacher_address": "123 Main St.",
        "teacher_phone_num": 1234567891,
        "student_name": "Bar",
        "student_address": "546 Main St.",
        "student_phone_num": 9184248576
    }

以上是一个愚蠢的例子,但它有助于说明我试图将上述内容反序列化为名为" Employee"的Java类的问题。使用杰克逊:

public class Employee {
    String name;
    String address;
    String phoneNumber;
}

问题是JSON有两个不同的prepends,所以我不能在Employee中注释每个字段,并将对象映射器映射teacher_name和student_name映射到Employee对象中的name字段。杰克逊有没有办法指定两个不同名称的节点来映射到同一个Java字段?

4 个答案:

答案 0 :(得分:3)

  

所以在我的例子中,我应该最终得到两个Employee对象(我保证每个响应有一对)

杰克逊不可能。它旨在将一对一映射:一个json对象映射到一个java对象。但是你想从一个json中得到两个java对象。

我建议您通过实施一些消耗Response的处理级别并将其映射到两个Employee对象来实现前进的方式。

答案 1 :(得分:0)

我认为无论是否使用注释,我都需要编写代码来进行映射。

简单是最好的。 如果你将json读作JsonNode,那么编写赋值应该是微不足道的。

import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;

public class Q44094751 {

   public static void main(String[] args) throws IOException {
      String json = "{\"id\": 1," +
            "\"teacher_name\": \"Foo\", \"teacher_address\": \"123 Main St.\", \"teacher_phone_num\": 1234567891," +
            "\"student_name\": \"Bar\", \"student_address\": \"546 Main St.\", \"student_phone_num\": 9184248576" +
         "}";
      ObjectMapper mapper = new ObjectMapper();
      // Read
      JsonNode node = mapper.readValue( json, JsonNode.class);
      Employee teacher = new Employee(),
               student = new Employee();
      teacher.name = node.get( "teacher_name" ).toString();
      teacher.address = node.get( "teacher_address" ).toString();
      teacher.phoneNumber = node.get( "teacher_phone_num" ).toString();
      student.name = node.get( "student_name" ).toString();
      student.address = node.get( "student_address" ).toString();
      student.phoneNumber = node.get( "student_phone_num" ).toString();
      // Check
      mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
      System.out.println( mapper.writeValueAsString( teacher ) );
   }

   public static class Employee {
      String name;
      String address;
      String phoneNumber;
   }
}
  

鉴于一个“愚蠢的例子”,答案可能看起来很愚蠢。   例如,如果你有一百个属性,带反射的循环应该会更好。

     

如果您的要求未在示例中反映出来,   请编辑您的问题,以便更好地描述您所面临的实际问题。

答案 2 :(得分:0)

我相信杰克逊是不可能的,我能想到的解决方法是

  1. 将其拆分为2个对象TeacherStudent。您仍然可以将同一个对象传递两次,但使用不同的类TeacherStudent,它可以正常工作,但id字段呢?

  2. 创建一个类似于JSON的Java类。

  3. 如果您想使其更具有完整结构,请使用此结构

    { "id": 1, "teacher" :{ "name": "Foo", "address": "123 Main St.", "phone_num": 1234567891, }, "student" :{ "name": "Bar", "address": "546 Main St.", "phone_num": 9184248576, } }

答案 3 :(得分:0)

您可以使用@JsonUnwrapped注释在父对象中内联展开员工的属性。此注释还提供了一个选项,用于指定在ser / der对象时使用的前缀名称。

以下是您的示例:

 public static class Employee {
        private String name;
        private String address;
        @JsonProperty("phone_num")
        private String phoneNumber;

        // setter / getter removed from brevity
    }

    public static class YourJsonObject {
        private int id;
        @JsonUnwrapped(prefix="teacher_")
        private Employee teacher;
        @JsonUnwrapped(prefix = "student_")
        private Employee student;

        // setter / getter removed from brevity
    }

现在配置ObjectMapper以使用适当的命名策略(从您的示例中,我看到了需要的蛇案策略)

测试用例:

   @Test
    public void peformTest() throws Exception {
        final String inputJson = "{\n" +
                "        \"id\": 1,\n" +
                "        \"teacher_name\": \"Foo\",\n" +
                "        \"teacher_address\": \"123 Main St.\",\n" +
                "        \"teacher_phone_num\": 1234567891,\n" +
                "        \"student_name\": \"Bar\",\n" +
                "        \"student_address\": \"546 Main St.\",\n" +
                "        \"student_phone_num\": 9184248576\n" +
                "    }";

        ObjectMapper mapper = new ObjectMapper();
        // important one
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

        // read your json as object
        YourJsonObject myObject = mapper.readValue(inputJson, YourJsonObject.class);

        assertThat(myObject.getTeacher().getName(), is("Foo"));
        assertThat(myObject.getStudent().getName(), is("Bar"));
    }

希望这有帮助。