package serializers.json; import java.io.*; import java.util.ArrayList; import java.util.List; import serializers.*; import data.media.Image; import data.media.Media; import data.media.MediaContent; /** * This serializer uses JSON-lib [http://json-lib.sourceforge.net] for JSON data binding. */ public class JsonLibJsonDatabind { public static void register(TestGroups groups) { groups.media.add(JavaBuiltIn.mediaTransformer, new GenericSerializer<MediaContent>("json/json-lib/databind", MediaContent.class), new SerFeatures( SerFormat.JSON, SerGraph.FLAT_TREE, SerClass.ZERO_KNOWLEDGE, "" ) ); } static class GenericSerializer<T> extends Serializer<T> { private final String name; private final Class<T> type; // private final net.sf.ezmorph.MorpherRegistry _morpherRegistry; private final net.sf.json.JsonConfig _jsonConfig; public GenericSerializer(String name, Class<T> clazz) { this.name = name; type = clazz; net.sf.ezmorph.MorpherRegistry _morpherRegistry = net.sf.json.util.JSONUtils.getMorpherRegistry(); _morpherRegistry.registerMorpher(new net.sf.json.util.EnumMorpher(Media.Player.class)); _morpherRegistry.registerMorpher(new net.sf.json.util.EnumMorpher(Image.Size.class)); // "preferred" approach with BeanMorpher causes excessive info logging // net.sf.ezmorph.Morpher imageMorpher = new net.sf.ezmorph.bean.BeanMorpher(Image.class, _morpherRegistry); // _morpherRegistry.registerMorpher(imageMorpher); _jsonConfig = new net.sf.json.JsonConfig(); _jsonConfig.setRootClass(type); // else JSON null is turned into empty string, which fails equality tests _jsonConfig.registerDefaultValueProcessor(String.class, new net.sf.json.processors.DefaultValueProcessor() { @Override public Object getDefaultValue(Class type) { return net.sf.json.JSONNull.getInstance(); } }); } public String getName() { return name; } @SuppressWarnings("unchecked") public T deserialize(byte[] array) throws Exception { String jsonInput = new String(array, "UTF-8"); net.sf.json.JSONObject jsonObject = net.sf.json.JSONObject.fromObject(jsonInput); T result = (T) net.sf.json.JSONObject.toBean(jsonObject, _jsonConfig); // JSON-lib cannot deserialize into a list of a custom type, when the list is a member of something. // Instead, JSON-lib populates the list with MorphDynaBeans, which can be transformed to the target type. MediaContent mediaContent = (MediaContent) result; int size = mediaContent.images.size(); List<Image> replacementImages = new ArrayList<Image> (size); for (int i = 0; i < size; i++) { // "preferred" approach with BeanMorpher causes excessive info logging -- TODO: figure out how to config // Object image = mediaContent.images.get(i); // replacementImages.add((Image)_morpherRegistry.morph(Image.class, image)); // alternate approach, still using JSON-lib components to transform data Object o = mediaContent.images.get(i); net.sf.ezmorph.bean.MorphDynaBean image = (net.sf.ezmorph.bean.MorphDynaBean) o; net.sf.json.JSONObject imageJsonObject = net.sf.json.JSONObject.fromObject(image); Image replacementImage = (Image) net.sf.json.JSONObject.toBean(imageJsonObject, Image.class); // a slightly "manual" approach (?) that is about 10% faster, but isn't it cheating? //Image replacementImage = new Image(); //replacementImage.height = (Integer) image.get("height"); //replacementImage.size = Image.Size.valueOf((String) image.get("size")); //replacementImage.title = (String) image.get("title"); //replacementImage.uri = (String) image.get("uri"); //replacementImage.width = (Integer) image.get("width"); replacementImages.add(replacementImage); } mediaContent.images = replacementImages; return result; } public byte[] serialize(T data) throws IOException { StringWriter w = new StringWriter(); net.sf.json.JSONSerializer.toJSON(data, _jsonConfig).write(w); w.flush(); return w.toString().getBytes("UTF-8"); } } }