简体   繁体   中英

How to deserialize multiple objects sequentially using jackson-databind

I am using msgpack to serialize data. I have some code works fine with serializing data.

public void testJackson() throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();

    String data1 = "test data";
    int data2 = 10;
    List<String> data3 = new ArrayList<String>();
    data3.add("list data1");
    data3.add("list data1");

    ObjectMapper mapper = new ObjectMapper();
    mapper.writeValue(out, data1);
    mapper.writeValue(out, data2);
    mapper.writeValue(out, data3);

    // TODO: How to deserialize?

}

But now I don't know how to deserialize data. I am not finding any solution anywhere. It will be good if anyone can help how to proceed.

您将要使用ObjectMapperreadValue方法之一-可能是将Reader或InputStream作为第一个参数的方法。

The problem

I have tried many of the readValue methods, but I only can get the first String, about the second and third value I have no idea

The thing is, Jackson always reads the first data, since the data is neither deleted from the nor did you explicitly tell Jackson that the next data is from position A to position B

Solutions

this example works and is similar to your code, but is not very elegant. Here I explicitly tell Jackson where my data is, but I have to know how it got written, which is a way too specific solution

File dataFile = new File("jackson.txt");
if(!dataFile.exists())
  dataFile.createNewFile();
FileOutputStream fileOut = new FileOutputStream(dataFile);
ByteArrayOutputStream out = new ByteArrayOutputStream();
FileInputStream fileIn = new FileInputStream(dataFile);

String writeData1 = "test data";
int writeData2 = 10;
List<String> writeData3 = new ArrayList<String>();
writeData3.add("list data1");
writeData3.add("list data1");

ObjectMapper mapper = new ObjectMapper();
byte[] writeData1Bytes = mapper.writeValueAsBytes(writeData1);
out.write(writeData1Bytes);
byte[] writeData2Bytes = mapper.writeValueAsBytes(writeData2);
out.write(writeData2Bytes);
byte[] writeData3Bytes = mapper.writeValueAsBytes(writeData3);
out.write(writeData3Bytes);
out.writeTo(fileOut);

// TODO: How to deserialize?
int pos = 0;
byte[] readData = new byte[1000];
fileIn.read(readData);
String readData1 = mapper.readValue(readData, pos, writeData1Bytes.length, String.class);
pos += writeData1Bytes.length;
Integer readData2 = mapper.readValue(readData, pos, writeData2Bytes.length, Integer.class);
pos += writeData2Bytes.length;
ArrayList readData3 = mapper.readValue(readData, pos, writeData3Bytes.length, ArrayList.class);
pos += writeData3Bytes.length;

System.out.printf("readData1 = %s%n", readData1);
System.out.printf("readData2 = %s%n", readData2);
System.out.printf("readData3 = %s%n", readData3);

the file looks then like this

"test data"10["list data1","list data1"]

How to do it correctly

a way more elegant way is to encapsulate your data in an object which can be turned into a valid JSON string and from that Jackson won't need any more information

public class JacksonTest {
  public static class DataNode {
    @JsonProperty("data1")
    private String data1;
    @JsonProperty("data2")
    private int data2;
    @JsonProperty("data3")
    private List<String> data3;

    //needed for Jackson
    public DataNode() {
    }

    public DataNode(String data1, int data2, List<String> data3) {
      this.data1 = data1;
      this.data2 = data2;
      this.data3 = data3;
    }
  }

  public static void main(String[] args) throws Exception {
    File dataFile = new File("jackson.txt");
    if(!dataFile.exists())
      dataFile.createNewFile();
    FileOutputStream fileOut = new FileOutputStream(dataFile);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    FileInputStream fileIn = new FileInputStream(dataFile);

    String writeData1 = "test data";
    int writeData2 = 10;
    List<String> writeData3 = new ArrayList<String>();
    writeData3.add("list data1");
    writeData3.add("list data1");

    DataNode writeData = new DataNode(writeData1, writeData2, writeData3);

    ObjectMapper mapper = new ObjectMapper();
    mapper.writeValue(out, writeData);
    out.writeTo(fileOut);

    // TODO: How to deserialize?
    DataNode readData = mapper.readValue(fileIn, DataNode.class);

    System.out.printf("readData1 = %s%n", readData.data1);
    System.out.printf("readData2 = %s%n", readData.data2);
    System.out.printf("readData3 = %s%n", readData.data3);
  }
}

the content of the file looks like this

{"data1":"test data","data2":10,"data3":["list data1","list data1"]}

@Japu_D_Cret Thank you for such a detailed answer! Actually I want to use msgpack to transfer data, and I made it work by using msgpack, here is my code

    ByteArrayOutputStream out = new ByteArrayOutputStream();

    String data1 = "test data";
    int data2 = 10;
    List<String> data3 = new ArrayList<String>();
    data3.add("list data1");
    data3.add("list data1");

    MessagePack packer = new MessagePack();

    packer.write(out, data1);
    packer.write(out, data2);
    packer.write(out, data3);

    // TODO: How to deserialize?

    BufferUnpacker unpacker = packer.createBufferUnpacker(out.toByteArray());
    System.out.println(unpacker.readString());
    System.out.println(unpacker.readInt());
    System.out.println(unpacker.read(Templates.tList(Templates.TString)));

Then I found jackson-databind on msgpack website and it supports msgpack format also. I do some tests on these two and found that jackson's serialize performance is better than msgpack, so I want to use jackson instead of msgpack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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