繁体   English   中英

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

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

我的服务可以接收几个不同的 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
}

或者

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

或其他几个json。 所有 json 唯一相同的字段是“事件”。 所有其他字段可以不同(取决于“事件”值)。

所以问题是:如何将这些 json 转换为 java 对象(不编写混乱的代码)? 我知道的唯一方法是手动检查“事件”值(如json.startsWith("{\n\"event\":\"message\"")但我确信这样做有任何简单的决定.

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

如下声明一个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();
        }
    }
}

使用 JSON object。 这是动态的,可以加载任何 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,检查类型,然后创建 object。 使用字符串解析器时要非常小心,因为您可能有也可能没有新行之类的东西。 相反,请执行以下操作:

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

当然,这要求所有类都有一个具体的 POJO 以允许反序列化。

另一种方法是做许多其他编程语言所做的事情,并拥有一个键/值 map。 有几种方法可以做到这一点。 一种是使用 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 并根据需要进行提取。 请注意,您仍然需要了解 JSON 的结构,但您不需要 POJO。

最后是第二种解决方案的变体。 使用JSONPath ,您可以直接提取您需要的内容。 同样,您需要先查看您拥有的事件类型。 就像是:

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

最后两种方法要求您一次提取一个值,如图所示。 第一个解决方案为您提供了一个完整的 object 可供使用。 您可以自行决定什么在您的环境中最有效。

暂无
暂无

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

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