使 JsonNode 可序列化

4

看起来很简单,但我无法将序列化的JsonNode反序列化。这是我的测试类:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Foo implements Serializable {
    private String string;
    private transient JsonNode jsonNode;

    public Foo(String string, JsonNode jsonNode) {
        this.string = string;
        this.jsonNode = jsonNode;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        if (this.jsonNode != null) out.writeObject((new ObjectMapper()).writeValueAsBytes(this.jsonNode));
//        out.writeObject(this.jsonNode.textValue());
    }

    private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {
        in.defaultReadObject();
        this.jsonNode = (new ObjectMapper()).readValue(in, JsonNode.class);
    }
}

当我尝试反序列化时,出现了这个错误。
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input

这是单元测试

import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.testng.annotations.Test;

import java.io.*;

import static org.testng.Assert.assertEquals;

public class FooTest {
    @Test
    public void testSerialization() {
        JsonNodeFactory nodeFactory = new JsonNodeFactory(false);
        ObjectNode node = nodeFactory.objectNode();
        ObjectNode child = nodeFactory.objectNode(); // the child
        child.put("message", "test");
        node.put("notification", child);

        Foo foo = new Foo("Bar", node);

        String fileName = "foo.ser";
        try (
                OutputStream file = new FileOutputStream(fileName);
                OutputStream buffer = new BufferedOutputStream(file);
                ObjectOutput output = new ObjectOutputStream(buffer);
        ){
            output.writeObject(foo);
        }
        catch(IOException ex){
            ex.getStackTrace();
        }

        Foo fooNew = null;

        //deserialize the ser file
        try(
                InputStream file = new FileInputStream(fileName);
                InputStream buffer = new BufferedInputStream(file);
                ObjectInput input = new ObjectInputStream (buffer);
        ){
            //deserialize the Object
            fooNew = (Foo) input.readObject();
        }
        catch(ClassNotFoundException ex){
            ex.printStackTrace();
        }
        catch(IOException ex){
            ex.printStackTrace();
        }

        assertEquals(foo, fooNew);
    }
}

3
为什么不直接将数据序列化为JSON格式?为什么要对JsonNode本身进行序列化? - Vivin Paliath
另一个建议是始终通过ObjectMapper操作(创建、序列化、反序列化)JsonNodeJsonNodeFactory仅用于内部(重新)配置和覆盖。 - StaxMan
1个回答

4
你的读写操作不匹配。
在写入方面,你使用 ObjectOutputStream.writeObject(Object) 写入一个包含序列化 JSON 内容的 byte[]。而在读取方面,你尝试使用 ObjectMapper.readValue(InputStream, Class) 从流中读取原始字节,实际上你需要先读取一个 byte[] 对象,因为这是你写入的内容,然后使用 ObjectMapper.readValue(byte[], Class)
或者更好的解决方案是,在写入方面你可以使用 ObjectMapper.writeValue(OutputStream, Object)
请尝试以下内容:
private void writeObject(ObjectOutputStream out) throws IOException {
    out.defaultWriteObject();
    if(jsonNode == null){
        out.writeBoolean(false);
    } else {
        out.writeBoolean(true);
        new ObjectMapper().configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false).writeValue(out, jsonNode);
    }
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    if(in.readBoolean()){
        this.jsonNode = new ObjectMapper().configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false).readValue(in, JsonNode.class);
    }     
}

我选择了后者,它看起来更对称。谢谢! - datree
您应该另外开一个问题,因为 NotSerializableException 与原始问题无关。话虽如此,当尝试序列化一个未实现 java.io.Serializable 接口的对象时,会出现 NotSerializableExceptionmisc.test.SerializationTest 可能没有实现 java.io.Serializable 接口。 - Dev
那是我的错。NonSerializable是由于内部类引起的。现在我已经将其移出,只看到java.io.IOException:Stream Closed错误。请查看更新后的代码。调试显示readObject实际上可以反序列化字符串和joshed。但之后,异常发生了。也许InputObjectStream的关闭不当? - datree
@datree 请查看添加的代码示例。问题在于ObjectMapper默认关闭流,需要将该功能关闭。 - Dev
1
请注意,对于最近版本的Jackson,为了使代码片段编译通过,必须将ObjectOutputStream转换为OutputStream,因为存在一个重载方法接受DataOutput参数的签名冲突。 - Jan-Willem Gmelig Meyling
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接