is it possible to controll field order in serialization with Jackson Smile dataformat

32 views Asked by At

I have a simple Java class that looks like this:

public class AnnotationData implements Serializable {

    public AnnotationData(String filename) {
        this.filename = filename;
    }

    private List<AnnotationLine> annotationLines = new ArrayList<>();

    private int widestRevision;

    private int widestAuthor;

    private String filename;

    private String revision;

    // getters and setters for the above fields omitted
}

The AnnotationLine is another simple Serializable class, with 3 fields (String, String, boolean).

The instances of the AnnotationData class are serialized and deserialized using the Smile dataformat in Jackson:

private void writeCache(AnnotationData annotationData, File outfile) throws IOException {
        ObjectMapper mapper = new SmileMapper();
        mapper.writeValue(outfile, annotationData);
}

static Annotation readCache(File file) throws IOException {
        ObjectMapper mapper = new SmileMapper();
        return new Annotation(mapper.readValue(file, AnnotationData.class));
}

In some cases, I'd like to avoid reading the whole file (esp. the potentially long annotationLines list) and just read the revision field.

Looking at the encoding of an instance, I can see the revision field being near the start of the file:

0000000   :   )  \n 001   � 215   w   i   d   e   s   t   R   e   v   i
0000010   s   i   o   n   � 213   w   i   d   e   s   t   A   u   t   h
0000020   o   r   $   � 207   f   i   l   e   n   a   m   e   G   c   l
0000030   i   e   n   t   .   c 207   r   e   v   i   s   i   o   n   Q
0000040   1   5   4   3   1   :   5   b   1   8   b   4   1   4   4   5
0000050   8   2 204   l   i   n   e   s   �   �   C   @   0 205   a   u
0000060   t   h   o   r   P   s   t   e   v   e   l   @   t   o   n   i
...
00126b0   3   1   C   6   0   3   5   C   5   7   7   7   B   4   0   7
00126c0   �   �                                                        
00126c2

which is actually what I need, however need some guarantees for the ordering.

So, my question has 2 parts:

  • is it possible to control the location of a particular field in the encoded file, e.g. via Jackson Java annotation (sic) ? (i.e. ensure that some fields will be serialized first)
  • assuming yes, what would be the code to deserialize just that field ? (thus to avoid going through the whole file)

Code examples are welcome.

1

There are 1 answers

0
Vlad On

Firstly, make sure the revision field in AnnotationData is serialized as the first field, by using this annotation:

@JsonPropertyOrder({"revision"})

One can specify multiple fields, here the one is sufficient.

Next, use the parser directly to read the value of the revision field:

        SmileFactory factory = new SmileFactory();
        try (SmileParser parser = factory.createParser(file)) {
            parser.nextToken();
            while (parser.getCurrentToken() != null) {
                if (parser.getCurrentToken().equals(JsonToken.FIELD_NAME)) {
                    break;
                }
                parser.nextToken();
            }

            if (parser.getCurrentName().equals("revision")) {
                parser.nextToken();
                if (!parser.getCurrentToken().equals(JsonToken.VALUE_STRING)) {
                    return null;
                }
                return parser.getValueAsString();
            } else {
                return null;
            }
        }

Keep in mind that Jackson uses 8000 byte read buffer by default so this will save the I/O only on bigger files.