【问题标题】:Parse all jsons that are concatenated in one string in Java解析Java中连接在一个字符串中的所有json
【发布时间】:2018-08-13 11:03:34
【问题描述】:

我有许多 json 对象连接成一个字符串,并且需要解析所有这些对象。简单例子:

String jsonStr = "{"name":"peter","age":40}{"name":"laura","age":50}"

当使用 jackson 的 ObjectMapper 解析此内容时,它会正确找到并读取第一个 json,并删除字符串的其余部分。

ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonStr);
System.out.println(rootNode);

输出{"name":"peter","age":20}

有什么方法(在杰克逊或其他框架中),例如返回读取的字符数,或字符串的其余部分,或JsonNodes 的数组?

我在JavaScriptPython 中发现了具有相同目标的问题,建议通过}{ 或正则表达式拆分以将其重新格式化为json 数组,但我仍然希望有一个更优雅的解决方案。

【问题讨论】:

  • 只需附加一个] 并在前面加上一个[,然后将其作为数组读取
  • [{"name":"peter","age":40},{"name":"laura","age":50}]这样用。
  • @Lino 仍然,你需要在 json 对象之间添加逗号
  • 我无法控制输入,必须按原样解析。方括号很容易,但插入逗号并非易事,以防故障的方式进行,并带来一些其他问题,这就是为什么我想尽可能避免这种情况。

标签: java json jackson


【解决方案1】:

您不需要按照其他人的建议修改您的输入,只需使用以下代码即可。

主要方法

public static void main(String[] args) throws IOException {

    ObjectMapper mapper = new ObjectMapper();
    JsonFactory factory = new JsonFactory(mapper);

    JsonParser parser = factory.createParser(new File("config.json"));
    // factory.createParser(String) and many other overload methods
    // available, byte[], char[], InputStream etc.

    Iterator<Person> persons = parser.readValuesAs(Person.class);
    while(persons.hasNext()) {
        Person p = persons.next();
        System.out.printf("%s: %d%n", p.getName(), p.getAge());
    }
}

人员类

public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}  

config.json 文件

{"name":"peter","age":40}{"name":"laura","age":50}

程序输出

peter: 40
laura: 50

使用的库

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.5</version>
</dependency>

【讨论】:

  • 太好了,这让我走上了正轨,非常感谢。您是否偶然知道如何处理不完整的数据(例如,将 {"name":"peter","age":40}{"name":"lau 作为输入)?找到this thread,不幸的是,它给出了一个不太好的解决方案。
  • @Bastian35022 为什么你的工作是修复无效数据?如果有人使用无效数据执行您的代码,那么它应该退出并抛出异常。
  • @Lino 数据不完整可能是由于通过 TCP 套接字传递数据而发生的,这是很常见的情况,如果没有 TCP 之上的任何协议将数据重组为完整的应用层数据包,则无法避免这种情况。如果数据不完整,我只需要等待更多数据到达,或者在连接中断的情况下丢弃它。
  • 那么没有必要尝试解析那个输入,因为你要么等待要么扔掉它
  • 它是一个实时应用程序,对延迟的要求比普通的 Web 应用程序要强。完整的json对象应该尽快解析处理,但是可能会出现得到部分json对象的情况,需要解决。
【解决方案2】:

在 Json 中,对象结构以{ 开头,以} 结尾。因此,ObjectMapper 认为只要遇到},就没有什么需要处理的了。

在 Json 中,数组用[] 表示。因此,如果您希望拥有多个元素/对象,则需要用 [] 括起来并用逗号分隔各个对象

"[
  {"name":"peter","age":40},
  {"name":"laura","age":50}
]"

【讨论】:

  • 在这里插入逗号是问题所在。当然这是可能的,但会使代码更丑陋并增加不必要的复杂性,这就是所描述的解决方案会受到赞赏的原因。
【解决方案3】:

您可以将输入用括号[] 包裹起来,然后将每个}{ 替换为},{,最后将字符串解析为数组:

String input = "{\"name\":\"peter\",\"age\":40}{\"name\":\"laura\",\"age\":50}"
String jsonArray = "[" + input.replace("}{", "},{") + "]";

ObjectMapper mapper = new ObjectMapper();
JsonNode parsedJsonArray = mapper.readTree(jsonArray);

【讨论】:

  • 当然可以,但会使代码更丑陋并增加不必要的复杂性,这就是所描述的解决方案值得赞赏的原因。
【解决方案4】:

你必须修改你的 JSON

String jsonStr = "[{\"name\":\"peter\",\"age\":40},{\"name\":\"laura\",\"age\":50}]";

有多种方法可以将 JSON 转换为 java 对象。

第一种方式

public JsonNode convertIntoJsonNode(String jsonStr)
    {
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = null;
        try {
            rootNode = objectMapper.readTree(jsonStr);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return rootNode;
    }

第二种方式 // 检查导入

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
// User Model
    class User{
        private String name;
        private Integer age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "User [name=" + name + ", age=" + age + "]";
        }
    }
//Coversion Method
public List<User> convertIntoObject(String jsonStr)
    {
        ObjectMapper objectMapper = new ObjectMapper();
        User[] myObjects = null;
        try {
            myObjects = objectMapper.readValue(jsonStr, User[].class);


        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return Arrays.asList(myObjects);
    }

第三种不用数组直接解析的方法

public List<User> convertIntothirdway(String jsonStr)
    {
        ObjectMapper objectMapper = new ObjectMapper();
        List<User> userList = null;
        try {
             userList = objectMapper.readValue(jsonStr, new TypeReference<List<User>>(){});
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return userList;
    }

第四条路

List<User> userList = mapper.readValue(jsonInput, mapper.getTypeFactory().constructCollectionType(List.class, User.class));

【讨论】:

  • 第二条路在哪里?
  • 添加第二种方式
  • 很遗憾,我无法更改输入。如前所述,我不希望应用基于字符串替换或正则表达式的修改。
  • 请检查您的 JSON 是否为无效 JSON。检查给定链接上的 josn jsonformatter.curiousconcept.com
  • @FaizAkram 请您仔细阅读问题,其中提到了多个有效的json对象被连接起来,他需要先读取有效的json,然后再读取第二个,以此类推。他还提到他知道一些需要替换 }{ 的解决方案,但他不喜欢它们。
猜你喜欢
  • 2012-08-06
  • 2012-05-13
  • 2015-04-30
  • 1970-01-01
  • 2011-04-23
  • 1970-01-01
  • 2020-05-19
  • 2021-02-03
相关资源
最近更新 更多