Handling Base64-encoded binary data with Jackson
Hopefully by now you know that Woodstox can handle base64-encoded binary data for your XML use cases. You may even know that Jackson can do the same for JSON (notice that "g.writeBinary()" call in Jackson Tutorial?)
But there is actually bit more to know about base64 functionality here. Let's first review core Base64 handling with 3 main processing models Jackson supports.
1. Handling base64-encoded binary with Streaming API
Assuming you get JSON content like:
{ "binary" : "hc3VyZS4=" }
you can get binary data out by, say:
JsonParser jp = new JsonFactory().createJsonParser(jsonStr); jp.nextToken(); // START_OBJECT jp.nextValue(); // VALUE_STRING that has base64 (skips field name as that's not a value) byte[] data = jp.getBinaryValue();
And if you want to produce similar data, you can do:
byte[] data = ...; StringWriter sw = new StringWriter(); JsonGenerator jg = new JsonFactory().createJsonGenerator(sw); jg.writeStartObject(); jg.writeFieldName("binary"); // 1.3 will have "writeBinaryField()" method jg.writeBinary(data, 0, data.length); jg.writeEndObject();
2. Handling base64-encoded binary with Data Binding
But where JsonParser and JsonGenerator make access quite easy, ObjectMapper makes it ridiculously easy. You just use 'byte[]' as the data type, and ObjectMapper binds data as expected.
static class Bean { public byte[] binary; } ObjectMapper mapper = new ObjectMapper(); Bean bean = mapper.readValue(jsonStr, Bean.class); byte[] data = bean.binary; // Want to serialize it? Sure: String outputStr = mapper.writeValueAsString(bean); // note: Jackson 1.3 only; otherwise use StringWriter
3. Handling base64-encoded binary with Tree Model
Handling binary data is almost as easy with Tree Model as well:
JsonNode object = mapper.readTree(jsonStr); JsonNode binaryNode = object.get("binary"); byte[] data = binaryNode.getBinaryValue(); // or construct from scratch, write? ObjectNode rootOb = mapper.createObjectNode(); rootOb.put("binary", rootOb.binaryNode(data)); outputStr = mapper.writeValueAsString(rootOb);
4. Additional Tricks
(DISCLAIMER: following features have been tested with Jackson 1.3, not yet released)
But what if you actually just want to encode or decode binary data to/from Base64-encoded Strings, outside context of JSON processing?
Turns out that you can do simple encoding and decoding quite easily. And
as an additional bonus, Jackson's strong focus on performance means that
the underlying codec is very efficient, even for "extra-curricular" use
(where output buffering is not utilized as it is for incremental JSON
processing).
In fact, it may just be faster than alternative commonly
used processing toolkits.
Anyway: to encode arbitrary binary data as, you can do:
import org.codehaus.jackson.node.BinaryNode; BinaryNode n = new BinaryNode(byteArray); String encodedText = n.getValueAsText();
// or as one-liner: encodedText = new BinaryNode(data).getValueAsText();
and to decode given Base64-encoded String, you can retrieve contained binary data by:
import org.codehaus.jackson.node.TextNode; TextNode n = new TextNode(encodedString); byte[] data = n.getBinaryValue();
// or as one-liner: data = new TextNode().getBinaryValue();
// or, if encoded using non-standard Base64 variant, try: data = n.getBinaryValue(Base64Variants.MODIFIED_FOR_URL);
Useful? Possibly -- no need to include Jakarta Commons Codec just for Base64 handling, if you happen to use Jackson already.