我有一个示例虚拟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字段?
答案 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)
我相信杰克逊是不可能的,我能想到的解决方法是
将其拆分为2个对象Teacher
和Student
。您仍然可以将同一个对象传递两次,但使用不同的类Teacher
和Student
,它可以正常工作,但id
字段呢?
创建一个类似于JSON的Java类。
如果您想使其更具有完整结构,请使用此结构
{
"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"));
}
希望这有帮助。