简体   繁体   English

如果我在解析之前不知道所有 Z466DEEC76ECDF2456D38571F6Z 字段,如何将 JSON 转换为 Java object?

[英]How to convert JSON to Java object if I do not know all json fields before parsing?

My service can receive several different jsons, such as:我的服务可以接收几个不同的 json,例如:

{
   "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
}

or或者

 {
   "event":"message",
   "message":{
      "type":"text",
      "text":"a message to the service",
      "location":{
         "lat":12.34,
         "lon":12.34
      }
   }
}

or several else jsons.或其他几个json。 The only field that is the same for all jsons is "event".所有 json 唯一相同的字段是“事件”。 All other fields can be different (depends on "event" value).所有其他字段可以不同(取决于“事件”值)。

So the question is: how to convert those jsons to java objects (without making messy code)?所以问题是:如何将这些 json 转换为 java 对象(不编写混乱的代码)? The only way I know is to manually check "event" value (like json.startsWith("{\n\"event\":\"message\"") but I'm sure that there is any simple decision for doing this.我知道的唯一方法是手动检查“事件”值(如json.startsWith("{\n\"event\":\"message\"")但我确信这样做有任何简单的决定.

UPD: If you don't want to convert JSON String to JAVA Object via declaring a POJO, you can parse it to JSONObject (com.alibaba.fastjson.JSONObject) UPD:如果您不想通过声明 POJO 将 JSON 字符串转换为 JAVA Object,则可以将其解析为JSONObject .

public class Event {

    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}}}";

        JSONObject jsonObject = JSONObject.parseObject(jsonA);
        String event = jsonObject.getString("event");
        if (event.equals("message")) {
            //do what you want to do
            System.out.println("message event......");
        } else if ("conversation_started".equals(event)) {
            System.out.println("context information event......");
        }
    }
}

Declaring a class of Event as below, and then convert JSON String to a Event JAVA object.如下声明一个Event的class,然后将JSON字符串转换为一个Event JAVA ZA8CFDE63311BD59EB26ACZF86。

@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();
        }
    }
}

Use a JSON object.使用 JSON object。 This is dynamic and can load any json.这是动态的,可以加载任何 json。 Then you can reference the event field consistently然后您可以一致地引用事件字段

Example 1示例 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")));

Example 2示例 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")));

There are three ways I've done this.我做了三种方法。 The first is to do what you're suggesting - parse the JSON, check the type, and create the object.首先是按照您的建议进行 - 解析 JSON,检查类型,然后创建 object。 Be very careful with using a String parser as you may or may not have things like new lines.使用字符串解析器时要非常小心,因为您可能有也可能没有新行之类的东西。 Instead, do something like:相反,请执行以下操作:

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 );
}

This, of course, requires all classes to have a concrete POJO to allow for deserialization.当然,这要求所有类都有一个具体的 POJO 以允许反序列化。

Another way is to do what many other programming languages do and have a key/value map.另一种方法是做许多其他编程语言所做的事情,并拥有一个键/值 map。 There are a few ways to do this.有几种方法可以做到这一点。 One is with the Jackson libraries:一种是使用 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"));

That way you can pass around the Map and extract as needed.这样您就可以绕过 Map 并根据需要进行提取。 Note that you still need to understand the structure of the JSON but you don't need to have a POJO for it.请注意,您仍然需要了解 JSON 的结构,但您不需要 POJO。

Lastly is a variation on the second solution.最后是第二种解决方案的变体。 Using JSONPath you can pull out what you need directly.使用JSONPath ,您可以直接提取您需要的内容。 Again you will want to first check out which type of event you have.同样,您需要先查看您拥有的事件类型。 Something like:就像是:

if( JsonPath.read(eventString, "$.event").equals("conversation_started") ) {
    String avatar = JsonPath.read(eventString, "$.user.avatar");
    System.out.println("conversation started - avatar is " + avatar);
 }

The last two methods require you to pull out values one at a time as shown.最后两种方法要求您一次提取一个值,如图所示。 The first solution gives you a full object to work with.第一个解决方案为您提供了一个完整的 object 可供使用。 It is your call as to what works best in your environment.您可以自行决定什么在您的环境中最有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM