package serializers.jackson;
import data.media.*;
import static data.media.FieldMapping.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.SerializedString;
import serializers.*;
/**
* "Hand-written" version of Jackson-based codec. Not optimized for compactness,
* but code is relatively simple monkey code even if bit verbose.
*/
public class JacksonJsonManual extends BaseJacksonDriver<MediaContent>
{
protected final static SerializedString FIELD_IMAGES = new SerializedString(FULL_FIELD_NAME_IMAGES);
protected final static SerializedString FIELD_MEDIA = new SerializedString(FULL_FIELD_NAME_MEDIA);
protected final static SerializedString FIELD_PLAYER = new SerializedString(FULL_FIELD_NAME_PLAYER);
protected final static SerializedString FIELD_URI = new SerializedString(FULL_FIELD_NAME_URI);
protected final static SerializedString FIELD_TITLE = new SerializedString(FULL_FIELD_NAME_TITLE);
protected final static SerializedString FIELD_WIDTH = new SerializedString(FULL_FIELD_NAME_WIDTH);
protected final static SerializedString FIELD_HEIGHT = new SerializedString(FULL_FIELD_NAME_HEIGHT);
protected final static SerializedString FIELD_FORMAT = new SerializedString(FULL_FIELD_NAME_FORMAT);
protected final static SerializedString FIELD_DURATION = new SerializedString(FULL_FIELD_NAME_DURATION);
protected final static SerializedString FIELD_SIZE = new SerializedString(FULL_FIELD_NAME_SIZE);
protected final static SerializedString FIELD_BITRATE = new SerializedString(FULL_FIELD_NAME_BITRATE);
protected final static SerializedString FIELD_COPYRIGHT = new SerializedString(FULL_FIELD_NAME_COPYRIGHT);
protected final static SerializedString FIELD_PERSONS = new SerializedString(FULL_FIELD_NAME_PERSONS);
public static void register(TestGroups groups)
{
JsonFactory factory = new JsonFactory();
groups.media.add(JavaBuiltIn.mediaTransformer, new JacksonJsonManual("json/jackson/manual",factory),
new SerFeatures(SerFormat.JSON,
SerGraph.FLAT_TREE,
SerClass.MANUAL_OPT,
""
)
);
}
private final JsonFactory _factory;
public JacksonJsonManual(String name, JsonFactory jsonFactory)
{
super(name);
_factory = jsonFactory;
}
@SuppressWarnings("resource")
@Override
public final byte[] serialize(MediaContent content) throws IOException
{
ByteArrayOutputStream baos = outputStream(content);
JsonGenerator generator = constructGenerator(baos);
writeMediaContent(generator, content);
generator.close();
return baos.toByteArray();
}
@Override
public final MediaContent deserialize(byte[] array) throws IOException
{
JsonParser parser = constructParser(array);
MediaContent mc = readMediaContent(parser);
parser.close();
return mc;
}
@Override
public final void serializeItems(MediaContent[] items, OutputStream out) throws IOException
{
JsonGenerator generator = constructGenerator(out);
// JSON allows simple sequences, so:
for (int i = 0, len = items.length; i < len; ++i) {
writeMediaContent(generator, items[i]);
}
generator.close();
}
@Override
public MediaContent[] deserializeItems(InputStream in, int numberOfItems) throws IOException
{
MediaContent[] result = new MediaContent[numberOfItems];
JsonParser parser = constructParser(in);
for (int i = 0; i < numberOfItems; ++i) {
result[i] = readMediaContent(parser);
}
parser.close();
return result;
}
// // // Internal methods
protected JsonParser constructParser(byte[] data) throws IOException {
return _factory.createParser(data, 0, data.length);
}
protected JsonParser constructParser(InputStream in) throws IOException {
return _factory.createParser(in);
}
protected JsonGenerator constructGenerator(OutputStream baos) throws IOException {
return _factory.createGenerator(baos, JsonEncoding.UTF8);
}
//////////////////////////////////////////////////
// Serialization
//////////////////////////////////////////////////
protected void writeMediaContent(JsonGenerator generator, MediaContent content) throws IOException
{
generator.writeStartObject();
generator.writeFieldName(FIELD_MEDIA);
writeMedia(generator, content.media);
generator.writeFieldName(FIELD_IMAGES);
generator.writeStartArray();
for (Image i : content.images) {
writeImage(generator, i);
}
generator.writeEndArray();
generator.writeEndObject();
}
private void writeMedia(JsonGenerator generator, Media media) throws IOException
{
generator.writeStartObject();
generator.writeFieldName(FIELD_PLAYER);
generator.writeString(media.player.name());
generator.writeFieldName(FIELD_URI);
generator.writeString(media.uri);
if (media.title != null) {
generator.writeFieldName(FIELD_TITLE);
generator.writeString(media.title);
}
generator.writeFieldName(FIELD_WIDTH);
generator.writeNumber(media.width);
generator.writeFieldName(FIELD_HEIGHT);
generator.writeNumber(media.height);
generator.writeFieldName(FIELD_FORMAT);
generator.writeString(media.format);
generator.writeFieldName(FIELD_DURATION);
generator.writeNumber(media.duration);
generator.writeFieldName(FIELD_SIZE);
generator.writeNumber(media.size);
if (media.hasBitrate) {
generator.writeFieldName(FIELD_BITRATE);
generator.writeNumber(media.bitrate);
}
if (media.copyright != null) {
generator.writeFieldName(FIELD_COPYRIGHT);
generator.writeString(media.copyright);
}
generator.writeFieldName(FIELD_PERSONS);
generator.writeStartArray();
for (String person : media.persons) {
generator.writeString(person);
}
generator.writeEndArray();
generator.writeEndObject();
}
private void writeImage(JsonGenerator generator, Image image) throws IOException
{
generator.writeStartObject();
generator.writeFieldName(FIELD_URI);
generator.writeString(image.uri);
if (image.title != null) {
generator.writeFieldName(FIELD_TITLE);
generator.writeString(image.title);
}
generator.writeFieldName(FIELD_WIDTH);
generator.writeNumber(image.width);
generator.writeFieldName(FIELD_HEIGHT);
generator.writeNumber(image.height);
generator.writeFieldName(FIELD_SIZE);
generator.writeString(image.size.name());
generator.writeEndObject();
}
//////////////////////////////////////////////////
// Deserialization
//////////////////////////////////////////////////
protected MediaContent readMediaContent(JsonParser parser) throws IOException
{
MediaContent mc = new MediaContent();
if (parser.nextToken() != JsonToken.START_OBJECT) {
reportIllegal(parser, JsonToken.START_OBJECT);
}
// first fast version when field-order is as expected
if (parser.nextFieldName(FIELD_MEDIA)) {
mc.media = readMedia(parser);
if (parser.nextFieldName(FIELD_IMAGES)) {
mc.images = readImages(parser);
parser.nextToken();
verifyCurrent(parser, JsonToken.END_OBJECT);
return mc;
}
}
// and fallback if order was changed
for (; parser.getCurrentToken() == JsonToken.FIELD_NAME; parser.nextToken()) {
String field = parser.getCurrentName();
Integer I = fullFieldToIndex.get(field);
if (I != null) {
switch (I) {
case FIELD_IX_MEDIA:
mc.media = readMedia(parser);
continue;
case FIELD_IX_IMAGES:
mc.images = readImages(parser);
continue;
}
}
throw new IllegalStateException("Unexpected field '"+field+"'");
}
verifyCurrent(parser, JsonToken.END_OBJECT);
if (mc.media == null) throw new IllegalStateException("Missing field: " + FIELD_MEDIA);
if (mc.images == null) mc.images = new ArrayList<Image>();
return mc;
}
private Media readMedia(JsonParser parser) throws IOException
{
if (parser.nextToken() != JsonToken.START_OBJECT) {
reportIllegal(parser, JsonToken.START_OBJECT);
}
Media media = new Media();
boolean haveWidth = false;
boolean haveHeight = false;
boolean haveDuration = false;
boolean haveSize = false;
// As with above, first fast path
if (parser.nextFieldName(FIELD_PLAYER)) {
media.player = Media.Player.find(parser.nextTextValue());
if (parser.nextFieldName(FIELD_URI)) {
media.uri = parser.nextTextValue();
if (parser.nextFieldName(FIELD_TITLE)) {
media.title = parser.nextTextValue();
if (parser.nextFieldName(FIELD_WIDTH)) {
haveWidth = true;
media.width = parser.nextIntValue(-1);
if (parser.nextFieldName(FIELD_HEIGHT)) {
haveHeight = true;
media.height = parser.nextIntValue(-1);
if (parser.nextFieldName(FIELD_FORMAT)) {
media.format = parser.nextTextValue();
if (parser.nextFieldName(FIELD_DURATION)) {
haveDuration = true;
media.duration = parser.nextLongValue(-1L);
if (parser.nextFieldName(FIELD_SIZE)) {
haveSize = true;
media.size = parser.nextLongValue(-1L);
if (parser.nextFieldName(FIELD_BITRATE)) {
media.bitrate = parser.nextIntValue(-1);
media.hasBitrate = true;
if (parser.nextFieldName(FIELD_COPYRIGHT)) {
media.copyright = parser.nextTextValue();
if (parser.nextFieldName(FIELD_PERSONS)) {
media.persons = readPersons(parser);
parser.nextToken();
verifyCurrent(parser, JsonToken.END_OBJECT);
return media;
}
}
}
}
}
}
}
}
}
}
}
// and if something reorder or missing, general loop:
for (; parser.getCurrentToken() == JsonToken.FIELD_NAME; parser.nextToken()) {
String field = parser.getCurrentName();
Integer I = fullFieldToIndex.get(field);
if (I != null) {
switch (I) {
case FIELD_IX_PLAYER:
media.player = Media.Player.find(parser.nextTextValue());
continue;
case FIELD_IX_URI:
media.uri = parser.nextTextValue();
continue;
case FIELD_IX_TITLE:
media.title = parser.nextTextValue();
continue;
case FIELD_IX_WIDTH:
media.width = parser.nextIntValue(-1);
haveWidth = true;
continue;
case FIELD_IX_HEIGHT:
media.height = parser.nextIntValue(-1);
haveHeight = true;
continue;
case FIELD_IX_FORMAT:
media.format = parser.nextTextValue();
continue;
case FIELD_IX_DURATION:
media.duration = parser.nextLongValue(-1L);
haveDuration = true;
continue;
case FIELD_IX_SIZE:
media.size = parser.nextLongValue(-1L);
haveSize = true;
continue;
case FIELD_IX_BITRATE:
media.bitrate = parser.nextIntValue(-1);
media.hasBitrate = true;
continue;
case FIELD_IX_PERSONS:
media.persons = readPersons(parser);
continue;
case FIELD_IX_COPYRIGHT:
media.copyright = parser.nextTextValue();
continue;
}
}
throw new IllegalStateException("Unexpected field '"+field+"'");
}
verifyCurrent(parser, JsonToken.END_OBJECT);
if (media.uri == null) throw new IllegalStateException("Missing field: " + FIELD_URI);
if (!haveWidth) throw new IllegalStateException("Missing field: " + FIELD_WIDTH);
if (!haveHeight) throw new IllegalStateException("Missing field: " + FIELD_HEIGHT);
if (media.format == null) throw new IllegalStateException("Missing field: " + FIELD_FORMAT);
if (!haveDuration) throw new IllegalStateException("Missing field: " + FIELD_DURATION);
if (!haveSize) throw new IllegalStateException("Missing field: " + FIELD_SIZE);
if (media.persons == null) media.persons = new ArrayList<String>();
if (media.player == null) throw new IllegalStateException("Missing field: " + FIELD_PLAYER);
return media;
}
private List<Image> readImages(JsonParser parser) throws IOException
{
if (parser.nextToken() != JsonToken.START_ARRAY) {
reportIllegal(parser, JsonToken.START_ARRAY);
}
List<Image> images = new ArrayList<Image>();
while (parser.nextToken() == JsonToken.START_OBJECT) {
images.add(readImage(parser));
}
verifyCurrent(parser, JsonToken.END_ARRAY);
return images;
}
private List<String> readPersons(JsonParser parser) throws IOException
{
if (parser.nextToken() != JsonToken.START_ARRAY) {
reportIllegal(parser, JsonToken.START_ARRAY);
}
List<String> persons = new ArrayList<String>();
String str;
while ((str = parser.nextTextValue()) != null) {
persons.add(str);
}
verifyCurrent(parser, JsonToken.END_ARRAY);
return persons;
}
private Image readImage(JsonParser parser) throws IOException
{
boolean haveWidth = false;
boolean haveHeight = false;
Image image = new Image();
if (parser.nextFieldName(FIELD_URI)) {
image.uri = parser.nextTextValue();
if (parser.nextFieldName(FIELD_TITLE)) {
image.title = parser.nextTextValue();
if (parser.nextFieldName(FIELD_WIDTH)) {
image.width = parser.nextIntValue(-1);
haveWidth = true;
if (parser.nextFieldName(FIELD_HEIGHT)) {
image.height = parser.nextIntValue(-1);
haveHeight = true;
if (parser.nextFieldName(FIELD_SIZE)) {
image.size = Image.Size.valueOf(parser.nextTextValue());
parser.nextToken();
verifyCurrent(parser, JsonToken.END_OBJECT);
return image;
}
}
}
}
}
for (; parser.getCurrentToken() == JsonToken.FIELD_NAME; parser.nextToken()) {
String field = parser.getCurrentName();
// read value token (or START_ARRAY)
parser.nextToken();
Integer I = fullFieldToIndex.get(field);
if (I != null) {
switch (I) {
case FIELD_IX_URI:
image.uri = parser.getText();
continue;
case FIELD_IX_TITLE:
image.title = parser.getText();
continue;
case FIELD_IX_WIDTH:
image.width = parser.getIntValue();
haveWidth = true;
continue;
case FIELD_IX_HEIGHT:
image.height = parser.getIntValue();
haveHeight = true;
continue;
case FIELD_IX_SIZE:
image.size = Image.Size.valueOf(parser.getText());
continue;
}
}
throw new IllegalStateException("Unexpected field '"+field+"'");
}
if (image.uri == null) throw new IllegalStateException("Missing field: " + FIELD_URI);
if (!haveWidth) throw new IllegalStateException("Missing field: " + FIELD_WIDTH);
if (!haveHeight) throw new IllegalStateException("Missing field: " + FIELD_HEIGHT);
if (image.size == null) throw new IllegalStateException("Missing field: " + FIELD_SIZE);
verifyCurrent(parser, JsonToken.END_OBJECT);
return image;
}
private final void verifyCurrent(JsonParser parser, JsonToken expToken) throws IOException
{
if (parser.getCurrentToken() != expToken) {
reportIllegal(parser, expToken);
}
}
private void reportIllegal(JsonParser parser, JsonToken expToken) throws IOException
{
JsonToken curr = parser.getCurrentToken();
String msg = "Expected token "+expToken+"; got "+curr;
if (curr == JsonToken.FIELD_NAME) {
msg += " (current field name '"+parser.getCurrentName()+"')";
}
msg += ", location: "+parser.getTokenLocation();
throw new IllegalStateException(msg);
}
}