如果在解析之前我不知道所有JSON字段,如何将JSON转换为Java对象?
我的服务可以接收多个不同的JSON,例如:如果在解析之前我不知道所有JSON字段,如何将JSON转换为Java对象?,java,json,Java,Json,我的服务可以接收多个不同的JSON,例如: { "event":"conversation_started", "context":"context information", "user":{ "id":"01234567890A=", "name":"John McClane", "avatar":"http://avatar.example.com", "country":"UK", "language":"en
{
"event":"conversation_started",
"context":"context information",
"user":{
"id":"01234567890A=",
"name":"John McClane",
"avatar":"http://avatar.example.com",
"country":"UK",
"language":"en",
"api_version":1
},
"subscribed":false
}
或
或者其他几个JSON。所有JSON唯一相同的字段是“event”。所有其他字段可以不同(取决于“事件”值)
所以问题是:如何将这些JSON转换为java对象(而不产生混乱的代码)?我知道的唯一方法是手动检查“event”值(如
json.startsWith(“{\n\”event\“:\”message\”)
,但我确信这样做有任何简单的决定。UPD:如果不想通过声明POJO将json字符串转换为JAVA对象,可以将其解析为JSONObject
(com.alibaba.fastjson.JSONObject)
如下所示声明一个Event
类,然后将JSON字符串转换为Event
JAVA对象
@Data
public class Event {
private String event;
private String context;
private User user;
private boolean subscribed;
private Message message;
@Data
public static class User {
private String id;
private String name;
private String avatar;
private String country;
private String language;
private int api_version;
}
@Data
public static class Message {
private String type;
private String text;
private Location location;
@Data
public static class Location {
private double lat;
private double lon;
}
}
public static void main(String[] args) {
String jsonA = "{\"event\":\"conversation_started\",\"context\":\"context information\",\"user\":{\"id\":\"01234567890A=\",\"name\":\"John McClane\",\"avatar\":\"http://avatar.example.com\",\"country\":\"UK\",\"language\":\"en\",\"api_version\":1},\"subscribed\":false}";
String jsonB = "{\"event\":\"message\",\"message\":{\"type\":\"text\",\"text\":\"a message to the service\",\"location\":{\"lat\":12.34,\"lon\":12.34}}}";
ObjectMapper objectMapper = new ObjectMapper();
try {
Event eventA = objectMapper.readValue(jsonA, new TypeReference<Event>() {
});
System.out.println(objectMapper.writeValueAsString(eventA));
Event eventB = objectMapper.readValue(jsonB, new TypeReference<Event>() {
});
System.out.println(objectMapper.writeValueAsString(eventB));
} catch (IOException e) {
e.printStackTrace();
}
}
}
@数据
公开课活动{
私有字符串事件;
私有字符串上下文;
私人用户;
私有布尔订阅;
私人信息;
@资料
公共静态类用户{
私有字符串id;
私有字符串名称;
私有字符串化身;
私人国家;
私有字符串语言;
私有int api_版本;
}
@资料
公共静态类消息{
私有字符串类型;
私有字符串文本;
私人位置;
@资料
公共静态类位置{
私人双lat;
私人双伦敦;
}
}
公共静态void main(字符串[]args){
字符串jsonA=“{\”事件\“:\”对话\”开始\“,\”上下文\“:\”上下文信息\“,\”用户\“:{\”id \“:\”01234567890A=\”,\“名称\“:\”约翰·麦克莱恩\“,”化身\“:\”http://avatar.example.com\“,”国家“:”英国“,”语言“:”en“,”api\U版本\“:1},\”订阅\“:false}”;
字符串jsonB=“{\'event\':\'message\',\'message\':{\'type\':\'text\',\'text\':\'a message to the service\',\'location\':{\'lat\':12.34,\'lon\':12.34}”;
ObjectMapper ObjectMapper=新的ObjectMapper();
试一试{
Event eventA=objectMapper.readValue(jsonA,new TypeReference(){
});
System.out.println(objectMapper.writeValueAsString(eventA));
eventB=objectMapper.readValue(jsonB,新类型引用(){
});
System.out.println(objectMapper.writeValueAsString(eventB));
}捕获(IOE异常){
e、 printStackTrace();
}
}
}
使用JSON对象。这是动态的,可以加载任何JSON。然后您可以一致地引用事件字段
例1
//import java.util.ArrayList;
//import org.bson.Document;
Document root = Document.parse("{ \"event\" : \"conversation_started\", \"context\" : \"context information\", \"user\" : { \"id\" : \"01234567890A=\", \"name\" : \"John McClane\", \"avatar\" : \"http://avatar.example.com\", \"country\" : \"UK\", \"language\" : \"en\", \"api_version\" : 1 }, \"subscribed\" : false }");
System.out.println(((String)root.get("event")));
例2
//import java.util.ArrayList;
//import org.bson.Document;
Document root = Document.parse("{ \"event\" : \"message\", \"message\" : { \"type\" : \"text\", \"text\" : \"a message to the service\", \"location\" : { \"lat\" : 12.34, \"lon\" : 12.34 } } }");
System.out.println(((String)root.get("event")));
我有三种方法可以做到这一点。第一种方法是按照您的建议来做——解析JSON,检查类型,然后创建对象。使用字符串解析器时要非常小心,因为您可能有或可能没有新行。相反,请执行以下操作:
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(eventString);
String eventType = jsonNode.get("event").asText();
if( eventType.equalsIgnoreCase("conversation_started")) {
// create ConversationStarted object using something like:
ConversationStarted conversationStarted = objectMapper.readValue( eventString, ConversationStarted.class );
}
if( JsonPath.read(eventString, "$.event").equals("conversation_started") ) {
String avatar = JsonPath.read(eventString, "$.user.avatar");
System.out.println("conversation started - avatar is " + avatar);
}
当然,这要求所有类都有一个具体的POJO,以允许反序列化
另一种方法是做许多其他编程语言做的事情,并有一个键/值映射。有几种方法可以做到这一点。一种是使用Jackson库:
Map<String, Object> map = objectMapper.readValue(eventString, new TypeReference<Map<String,Object>>(){});
Map<String, Object> user = (Map<String, Object>) map.get("user");
System.out.println( "conversation started - avatar is " + user.get("avatar"));
最后两种方法要求您一次提取一个值,如图所示。第一种解决方案为您提供了一个完整的对象来处理。这是您对在您的环境中最有效的方法的要求
Map<String, Object> map = objectMapper.readValue(eventString, new TypeReference<Map<String,Object>>(){});
Map<String, Object> user = (Map<String, Object>) map.get("user");
System.out.println( "conversation started - avatar is " + user.get("avatar"));
if( JsonPath.read(eventString, "$.event").equals("conversation_started") ) {
String avatar = JsonPath.read(eventString, "$.user.avatar");
System.out.println("conversation started - avatar is " + avatar);
}