2

Is there a way to make Jackson serialize some stream object (and close after)? like this:

class TextFile{
    String fileName;
    StringReader content;
    //ByteArrayInputStream content;
}

Update

Clarification: I want to stream the content, not just serialize it to a single String object.

Roman K
  • 3,309
  • 1
  • 33
  • 49

2 Answers2

2

Implement a custom JsonSerializer:

public class StreamSerializer extends JsonSerializer<ByteArrayInputStream> {

    @Override
    public void serialize(ByteArrayInputStream content, 
                          JsonGenerator jsonGenerator, 
                          SerializerProvider serializerProvider) 
                          throws IOException, JsonProcessingException {
        jsonGenerator.writeBinary(content, -1);
}

And use it like this:

public class TextFile {
    String fileName;
    @JsonSerialize(using=StreamSerializer.class, as=byte[].class)
    ByteArrayInputStream content;
}
hzpz
  • 7,536
  • 1
  • 38
  • 44
0

Your question is similar to: Jackson JSON custom serialization for certain fields

What is the desired behavior? Do you want the stream to be serialized as a string, as binary content, parsed and serialized as an object, etc.

Assuming you want the data serialized as a string, you could use an annotation to tell Jackson how to serialize it:

public class TextFile {
    String fileName;
    @JsonSerialize(using=ReaderToStringSerializer.class, as=String.class)
    StringReader content;
}


public class ReaderToStringSerializer extends JsonSerializer<Reader> {

@Override
public void serialize(Reader contents, 
                      JsonGenerator jsonGenerator, 
                      SerializerProvider serializerProvider) 
                      throws IOException, JsonProcessingException {
    StringBuilder buffer = new StringBuilder();
    char[] array = new char[8096];
    int len = 0;
    while (-1 != (len = contents.read(array))) {
        buffer.append(array,0,len);
    }
    contents.close();
    jsonGenerator.writeString(buffer.toString());
}

The output would be something like:

{
  "fileName": "foo.bar",
  "content": "the quick brown fox..."
}
Community
  • 1
  • 1
tombrown52
  • 482
  • 4
  • 13
  • 1
    Don't reinvent the well, use commons-io's `IOUtils#toString(Reader)` to get the contents of the `Reader` as `String`. – hzpz Jul 15 '15 at 20:25
  • 1
    this does not "stream" the content. `buffer.toString()` creates the whole string in memory and misses the whole point of using a stream in first place. – Roman K Jul 15 '15 at 20:37
  • I assumed you had the entire data in memory because you specified a *StringReader* in your question. Correctly streaming JSON output is more difficult than just reading bytes and writing bytes, as you have to correctly account for escaping characters and non-printable characters. If you want base64 output then the writeBinary solution (above) is correct. – tombrown52 Jul 15 '15 at 21:20
  • @tombrown52 How can I use the serialiser in order to send the response as a stream (downloading a file) rather than a json format? Does writeBinary work for this? – xbmono May 30 '17 at 07:21
  • @xbmono This whole thread is very dependent on the Jackson library. As such, it's mostly applicable to the JSON format, but would probably work for any other format Jackson supports (like YAML). AFAIK the Jackson API requires you to write only complete primitive values (no partial strings). However, I think that the jsonGenerator will output a stream of tokens (whole values and individual syntax characters such as "}"). I don't think that you have to do anything special to get this kind of streaming output from Jackson. If you ask your question as an actual SO question, I'll try and answer it. – tombrown52 May 30 '17 at 14:23