Created
November 9, 2012 06:59
-
-
Save wangzaixiang/4044143 to your computer and use it in GitHub Desktop.
Simple JSON-javabean mapping utility based on JAXB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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