【问题标题】:Make JsonNode Serializable使 JsonNode 可序列化
【发布时间】:2015-08-06 16:43:28
【问题描述】:

这似乎很简单,但我未能反序列化序列化的 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);
    }
}

【问题讨论】:

  • 为什么不直接序列化为 JSON?为什么要序列化 ​​JsonNode 本身?
  • 另一个建议是始终通过ObjectMapper 操作(创建、序列化、反序列化)JsonNode:JsonNodeFactory 仅用于内部(重新)配置和覆盖。

标签: java json serialization jackson


【解决方案1】:

您的读写操作不匹配。

在写入端,您使用 ObjectOutputStream.writeObject(Object) 编写包含序列化 JSON 内容的 byte[]。在读取方面,当您实际上需要首先读取 byte[] 对象时,您尝试使用 ObjectMapper.readValue(InputStream, Class) 从流中读取原始字节,因为这是您编写的,然后使用 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);
    }     
}

【讨论】:

  • 我选择了后者,看起来更加对称。谢谢!
  • 好吧,就像我认为它正在工作一样。我收到另一个错误 java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException:misc.test.SerializationTest。代码在github.com/songyangster/vertx-in-springboot/blob/master/src/… 中,如果我注释掉 out.defaultWriteObject();,我得到 java.io.IOException: Stream closed
  • 您可能应该打开另一个问题,因为NotSerializableException 与原始问题无关。话虽这么说,NotSerializableException 在尝试序列化未实现java.io.Serializable 的对象时发生。 misc.test.SerializationTest 可能没有实现 java.io.Serializable
  • 那是我的错。 NonSerializable 是由于内部类。现在我把它移走了,只看到 java.io.IOException: Stream Closed 错误。请查看更新后的代码。调试显示 readObject 实际上可以反序列化字符串和 joshed。但在那之后,异常发生了。可能是 InputObjectStream 关​​闭不当?
  • 请记住,对于最新版本的 Jackson,ObjectOutputStream 必须转换为 OutputStream 才能使 sn-p 编译,因为重载方法之间的签名冲突接受DataOutput。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-18
相关资源
最近更新 更多