Skip to content

Instantly share code, notes, and snippets.

@wangzaixiang
Created November 9, 2012 06:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wangzaixiang/4044143 to your computer and use it in GitHub Desktop.
Save wangzaixiang/4044143 to your computer and use it in GitHub Desktop.
Simple JSON-javabean mapping utility based on JAXB
package wangzx.util.json;
import java.io.IOException;
import javax.xml.transform.sax.SAXSource;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
/**
* JSONContentReader pipes a JSON input to a XML(SAXSource) output.
*
* using JSONContentReader with JAXB Unmarshaller:
* <code>
* JSONObject json; // your JSON value
* JSONContentReader reader = new JSONContentReader(json);
*
* Unmarshaller unmarshaller; // your jaxb unmarshaller
* JavaBean youBean = (JavaBean) unmarshaller.unmarshal(reader);
* </code>
*
* @see JSONContentWriter pipes a XML(SAXSource) input to a JSON output
*
* @author waltwang
*/
public class JSONContentReader extends SAXSource {
// the object can contains only 1 key as the xml root element
private JSONObject json;
class JsonXmlReader implements XMLReader {
private EntityResolver entityResolver;
private DTDHandler dtdHandler;
private ContentHandler contentHandler;
private ErrorHandler errorHandler;
@Override
public boolean getFeature(String name)
throws SAXNotRecognizedException, SAXNotSupportedException {
return false;
}
@Override
public void setFeature(String name, boolean value)
throws SAXNotRecognizedException, SAXNotSupportedException {
}
@Override
public Object getProperty(String name)
throws SAXNotRecognizedException, SAXNotSupportedException {
return null;
}
@Override
public void setProperty(String name, Object value)
throws SAXNotRecognizedException, SAXNotSupportedException {
}
@Override
public void setEntityResolver(EntityResolver resolver) {
this.entityResolver = resolver;
}
@Override
public EntityResolver getEntityResolver() {
return entityResolver;
}
@Override
public void setDTDHandler(DTDHandler handler) {
this.dtdHandler = handler;
}
@Override
public DTDHandler getDTDHandler() {
return dtdHandler;
}
@Override
public void setContentHandler(ContentHandler handler) {
this.contentHandler = handler;
}
@Override
public ContentHandler getContentHandler() {
return contentHandler;
}
@Override
public void setErrorHandler(ErrorHandler handler) {
this.errorHandler = handler;
}
@Override
public ErrorHandler getErrorHandler() {
return errorHandler;
}
@Override
public void parse(InputSource input) throws IOException, SAXException {
contentHandler.startDocument();
for(Object key: json.keySet()) {
if(key instanceof String){
String sKey = (String) key;
Object value = json.get(key);
visitJSON(contentHandler, sKey, value);
break;
}
}
contentHandler.endDocument();
}
@Override
public void parse(String systemId) throws IOException, SAXException {
throw new RuntimeException("parse with systemId not supported");
}
}
void visitJSON(ContentHandler ch, String key, Object value) throws SAXException {
AttributesImpl emptyAttrs = new AttributesImpl();
if(value != null && value instanceof JSONArray){
JSONArray array = (JSONArray) value;
for(int i = 0; i<array.size(); i++) {
Object elem = array.get(i);
visitJSON(ch, key, elem);
}
return;
}
ch.startElement(null, key, key, emptyAttrs);
do {
if(value == null) {
break;
}
if(value instanceof String) {
String str = (String) value;
ch.characters(str.toCharArray(), 0, str.length());
break;
}
if(value instanceof JSONObject) {
JSONObject jso = (JSONObject) value;
for(Object subKey: jso.keySet()){
if(subKey instanceof String) {
String subKeyStr = (String) subKey;
visitJSON(ch, subKeyStr, jso.get(subKeyStr));
}
}
break;
}
throw new AssertionError("Unknown json type:" + value.getClass());
} while(false);
ch.endElement(null, key, key);
}
public JSONContentReader(JSONObject jso){
this.json = jso;
super.setXMLReader(new JsonXmlReader());
}
}
package wangzx.util.json;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
/**
* JSONContentWriter pipes a a XML(ContentHandler) input event to JSON output.
*
* using JSONContentReader with JAXB marshaller:
* <code>
*
* Marshaller marshaller; // your jaxb marshaller
* JavaBean yourBean; // your jaxb bean
*
* JSONContentWriter jsonWriter = new JSONContentWriter();
* marshaller.marshal(yourBean, jsonWriter);
* JSONObject json = jsonWriter.toJSON();
* </code>
*
* @see JSONContentWriter pipes a XML(SAXSource) input to a JSON output
*
* @author waltwang
*/
public class JSONContentWriter implements ContentHandler {
static class Node {
Node parent;
List<Node> children = new ArrayList<Node>();
String name; // either elementTagName or @attributeName
String value; // if no children
public Object toJSON(){
if(children.size()==0)
return (value == null) ? "" : value;
Map<String, List<Node>> childsByName = new HashMap<String, List<Node>>();
for(Node it: children) {
if(childsByName.containsKey(it.name))
childsByName.get(it.name).add(it);
else {
ArrayList<Node> nodes = new ArrayList<Node>();
nodes.add(it);
childsByName.put(it.name, nodes);
}
}
JSONObject jso = new JSONObject();
for(String key: childsByName.keySet()){
List<Node> values = childsByName.get(key);
if(values.size() == 1) { // { "key": value }
jso.put(key, values.get(0).toJSON());
}
else {
JSONArray jsarray = new JSONArray();
for(Node it: values) jsarray.add(it.toJSON());
jso.put(key, jsarray);
}
}
return jso;
}
}
Node root;
Node current;
@Override
public void setDocumentLocator(Locator locator) {
//System.out.println("setDocumentLocator:locator" + locator);
}
@Override
public void startDocument() throws SAXException {
root = new Node();
current = root;
}
@Override
public void endDocument() throws SAXException {
//System.out.println("endDocument");
}
@Override
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
//System.out.println("startPrefixMapping:prefix=" + prefix + ";uri=" + uri);
}
@Override
public void endPrefixMapping(String prefix) throws SAXException {
//System.out.println("endPrefixMapping:" + prefix);
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes atts) throws SAXException {
System.out.println("startElement: uri=" + uri + ";localName=" + localName + ";qName=" + qName);
Node node = new Node();
node.parent = current;
node.name = localName;
current.children.add(node);
current = node;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("endElement: uri=" + uri + ";localName=" + localName + ";qName=" + qName);
current = current.parent;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//System.out.println("characters:" + new String(ch, start, length));
if(current.value != null)
current.value = current.value + new String(ch, start, length);
else
current.value = new String(ch, start, length);
}
@Override
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
//System.out.println("ignorableWhitespace:" + new String(ch, start, length));
}
@Override
public void processingInstruction(String target, String data)
throws SAXException {
//System.out.println("processingInstruction:target=" + target + ";data=" + data);
}
@Override
public void skippedEntity(String name) throws SAXException {
//System.out.println("skippedEntity:name=" + name);
}
public JSONObject toJSON() {
// the root node is always a JSONObject
return (JSONObject) root.toJSON();
}
}
package wangzx.util.json;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import net.sf.json.JSON;
import net.sf.json.JSONObject;
import net.sf.json.util.JSONTokener;
import org.junit.Assert;
import org.junit.Test;
public class TestJson {
@XmlAccessorType(XmlAccessType.FIELD)
static class Address {
String addr1;
String addr2;
String postcode;
}
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD)
static class Student {
String name;
int age;
List<Address> address = new ArrayList<TestJson.Address>();
}
@Test
public void testMarshal() throws Exception {
Student student = new Student();
student.name = "waltwang";
student.age = 39;
Address address1 = new Address();
address1.addr1 = "addr1";
address1.addr2 = "addr2";
address1.postcode = "510000";
Address address2 = new Address();
address2.addr1 = "ADDR1";
address2.addr2 = "ADDR2";
address2.postcode = "510001";
student.address.add(address1);
student.address.add(address2);
JAXBContext ctx = JAXBContext.newInstance(Student.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JSONContentWriter jsonWriter = new JSONContentWriter();
marshaller.marshal(student, jsonWriter);
JSON result = (JSON) jsonWriter.toJSON();
System.out.println( result.toString() );
}
@Test
public void testUnmarshal() throws Exception{
String input = "{\"student\":{\"address\":[{\"addr1\":\"addr1\",\"addr2\":\"addr2\",\"postcode\":\"510000\"},{\"addr1\":\"ADDR1\",\"addr2\":\"ADDR2\",\"postcode\":\"510001\"}],\"age\":\"39\",\"name\":\"waltwang\"}}";
JSONObject value = (JSONObject) new JSONTokener(input).nextValue();
JAXBContext ctx = JAXBContext.newInstance(Student.class);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
JSONContentReader jsonReader = new JSONContentReader(value);
Student student = (Student) unmarshaller.unmarshal(jsonReader);
marshaller.marshal(student, System.out);
Assert.assertEquals("waltwang", student.name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment