/******************************************************************************* | |
* Copyright (c) 2011, 2013 Oracle and/or its affiliates. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Blaise Doughan - 2.4 - initial implementation | |
******************************************************************************/ | |
package org.eclipse.persistence.internal.oxm.record.json; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Properties; | |
import javax.xml.namespace.QName; | |
import org.eclipse.persistence.exceptions.XMLMarshalException; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.ANTLRInputStream; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.ANTLRReaderStream; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.CharStream; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.RecognitionException; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.TokenRewriteStream; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.TokenStream; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.tree.CommonTree; | |
import org.eclipse.persistence.internal.libraries.antlr.runtime.tree.Tree; | |
import org.eclipse.persistence.internal.oxm.CollectionGroupingElementNodeValue; | |
import org.eclipse.persistence.internal.oxm.Constants; | |
import org.eclipse.persistence.internal.oxm.ContainerValue; | |
import org.eclipse.persistence.internal.oxm.MappingNodeValue; | |
import org.eclipse.persistence.internal.oxm.MediaType; | |
import org.eclipse.persistence.internal.oxm.NamespaceResolver; | |
import org.eclipse.persistence.internal.oxm.NodeValue; | |
import org.eclipse.persistence.internal.oxm.Root; | |
import org.eclipse.persistence.internal.oxm.XMLConversionManager; | |
import org.eclipse.persistence.internal.oxm.XPathFragment; | |
import org.eclipse.persistence.internal.oxm.mappings.Field; | |
import org.eclipse.persistence.internal.oxm.record.AbstractUnmarshalRecord; | |
import org.eclipse.persistence.internal.oxm.record.SAXUnmarshallerHandler; | |
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord; | |
import org.eclipse.persistence.internal.oxm.XPathNode; | |
import org.eclipse.persistence.internal.oxm.record.XMLReaderAdapter; | |
import org.eclipse.persistence.internal.oxm.record.deferred.DeferredContentHandler; | |
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy; | |
import org.eclipse.persistence.oxm.record.XMLRootRecord; | |
import org.xml.sax.ErrorHandler; | |
import org.xml.sax.InputSource; | |
import org.xml.sax.SAXException; | |
import org.xml.sax.SAXParseException; | |
import org.xml.sax.helpers.AttributesImpl; | |
public class JSONReader extends XMLReaderAdapter { | |
private static final String TRUE = "true"; | |
private static final String FALSE = "false"; | |
private Properties properties; | |
private String attributePrefix = null; | |
private NamespaceResolver namespaces = null; | |
private boolean includeRoot; | |
private String textWrapper; | |
private Class unmarshalClass; | |
private boolean isInCollection; | |
public JSONReader(String attrPrefix, NamespaceResolver nr, boolean namespaceAware, boolean includeRoot, Character namespaceSeparator, ErrorHandler errorHandler, String textWrapper){ | |
this(attrPrefix, nr, namespaceAware, includeRoot, namespaceSeparator, errorHandler, textWrapper, null); | |
} | |
public JSONReader(String attrPrefix, NamespaceResolver nr, boolean namespaceAware, boolean includeRoot, Character namespaceSeparator, ErrorHandler errorHandler, String textWrapper, Class unmarshalClass){ | |
this.attributePrefix = attrPrefix; | |
if(attributePrefix == Constants.EMPTY_STRING){ | |
attributePrefix = null; | |
} | |
namespaces = nr; | |
this.namespaceAware = namespaceAware; | |
if(namespaceSeparator == null){ | |
this.namespaceSeparator = Constants.DOT; | |
}else{ | |
this.namespaceSeparator = namespaceSeparator; | |
} | |
this.includeRoot = includeRoot; | |
this.setErrorHandler(errorHandler); | |
this.textWrapper = textWrapper; | |
this.unmarshalClass = unmarshalClass; | |
} | |
private JSONAttributes attributes = new JSONAttributes(); | |
@Override | |
public void parse(InputSource input) throws IOException, SAXException { | |
try { | |
CharStream charStream; | |
InputStream inputStream = null; | |
if(null != input.getByteStream()) { | |
charStream = new ANTLRInputStream(input.getByteStream()); | |
} else if (null != input.getCharacterStream()){ | |
charStream = new ANTLRReaderStream(input.getCharacterStream()); | |
} else { | |
try { | |
URL url = new URL(input.getSystemId()); | |
inputStream = url.openStream(); | |
} catch(MalformedURLException malformedURLException) { | |
try { | |
inputStream = new FileInputStream(input.getSystemId()); | |
} catch(FileNotFoundException fileNotFoundException) { | |
throw malformedURLException; | |
} | |
} | |
charStream = new ANTLRInputStream(inputStream); | |
} | |
JSONLexer lexer = new JSONLexer(charStream); | |
TokenRewriteStream tokens = new TokenRewriteStream(lexer); | |
ExtendedJSONParser parser = new ExtendedJSONParser(tokens, input, getErrorHandler()); | |
CommonTree commonTree = (CommonTree) parser.message().getTree(); | |
parseRoot(commonTree); | |
if(null != inputStream) { | |
inputStream.close(); | |
} | |
} catch(RecognitionException e) { | |
SAXParseException saxParseException = new SAXParseException(e.getLocalizedMessage(), input.getPublicId(), input.getSystemId(), e.line, e.index, e); | |
getErrorHandler().fatalError(saxParseException); | |
} catch(SAXExceptionWrapper e){ | |
throw e.getCause(); | |
} | |
} | |
@Override | |
public void parse(String systemId) { | |
try { | |
parse(new InputSource(systemId)); | |
} catch (IOException e) { | |
throw XMLMarshalException.unmarshalException(e); | |
} catch (SAXException e) { | |
throw XMLMarshalException.unmarshalException(e); | |
} | |
} | |
private void parseRoot(Tree tree) throws SAXException { | |
if(namespaces != null){ | |
Map <String, String> namespacePairs = namespaces.getPrefixesToNamespaces(); | |
Iterator<String> keys = namespacePairs.keySet().iterator(); | |
while(keys.hasNext()){ | |
String nextKey = keys.next(); | |
contentHandler.startPrefixMapping(nextKey, namespacePairs.get(nextKey)); | |
} | |
} | |
if(tree.getType() == JSONLexer.OBJECT){ | |
contentHandler.startDocument(); | |
int children = tree.getChildCount(); | |
if(children == 0 && unmarshalClass == null){ | |
return; | |
} | |
if(includeRoot){ | |
parse((CommonTree) tree.getChild(0)); | |
}else{ | |
if(children == 1){ | |
CommonTree ct = (CommonTree) tree.getChild(0); | |
if(ct != null && ct.getType() == JSONLexer.NULL){ | |
contentHandler.setNil(true); | |
} | |
contentHandler.startElement(Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, attributes.setTree(tree, attributePrefix, namespaces, namespaceSeparator, namespaceAware)); | |
parse(ct); | |
contentHandler.endElement(Constants.EMPTY_STRING,Constants.EMPTY_STRING, null); | |
}else{ | |
contentHandler.startElement(Constants.EMPTY_STRING, Constants.EMPTY_STRING, null, attributes.setTree(tree, attributePrefix, namespaces, namespaceSeparator, namespaceAware)); | |
for(int x=0, size=children; x<size; x++) { | |
parse((CommonTree) tree.getChild(x)); | |
} | |
contentHandler.endElement(Constants.EMPTY_STRING,Constants.EMPTY_STRING, null); | |
} | |
} | |
contentHandler.endDocument(); | |
} else if(tree.getType() == JSONLexer.ARRAY){ | |
SAXUnmarshallerHandler rootContentHandler = null; | |
if(getContentHandler() instanceof SAXUnmarshallerHandler) { | |
rootContentHandler = (SAXUnmarshallerHandler)getContentHandler(); | |
} | |
int size = tree.getChildCount(); | |
List list = new ArrayList(size); | |
for(int x=0; x<size; x++) { | |
parseRoot(tree.getChild(x)); | |
if(getContentHandler() instanceof SAXUnmarshallerHandler) { | |
SAXUnmarshallerHandler saxUnmarshallerHandler = (SAXUnmarshallerHandler) contentHandler; | |
list.add(saxUnmarshallerHandler.getObject()); | |
saxUnmarshallerHandler.setObject(null); | |
} else if(getContentHandler() instanceof UnmarshalRecord) { | |
UnmarshalRecord unmarshalRecord = (UnmarshalRecord) contentHandler; | |
Object unmarshalledObject = unmarshalRecord.getCurrentObject(); | |
if(includeRoot && unmarshalClass != null){ | |
if(!(unmarshalledObject instanceof Root)) { | |
Root xmlRoot = unmarshalRecord.createRoot(); | |
xmlRoot.setNamespaceURI(unmarshalRecord.getRootElementNamespaceUri()); | |
xmlRoot.setLocalName(unmarshalRecord.getLocalName()); | |
xmlRoot.setObject(unmarshalledObject); | |
unmarshalledObject = xmlRoot; | |
} | |
} | |
list.add(unmarshalledObject); | |
unmarshalRecord.setCurrentObject(null); | |
unmarshalRecord.setRootElementName(null); | |
unmarshalRecord.setLocalName(null); | |
} | |
} | |
if(getContentHandler() instanceof SAXUnmarshallerHandler) { | |
((SAXUnmarshallerHandler) getContentHandler()).setObject(list); | |
} else if(getContentHandler() instanceof UnmarshalRecord) { | |
((UnmarshalRecord) getContentHandler()).setCurrentObject(list); | |
((UnmarshalRecord) getContentHandler()).setRootElementName(Constants.EMPTY_STRING); | |
((UnmarshalRecord) getContentHandler()).setLocalName(Constants.EMPTY_STRING); | |
if(rootContentHandler != null){ | |
rootContentHandler.setObject(list); | |
} | |
} | |
} else { | |
getContentHandler().startDocument(); | |
parse(tree); | |
} | |
} | |
private void parse(Tree tree) throws SAXException { | |
if(tree == null){ | |
return; | |
} | |
switch(tree.getType()) { | |
case JSONLexer.PAIR: { | |
Tree valueTree = tree.getChild(1); | |
if(valueTree.getType() == JSONLexer.ARRAY) { | |
parse(valueTree); | |
} else { | |
Tree stringTree = tree.getChild(0); | |
String qualifiedName = stringTree.getText().substring(1, stringTree.getText().length() - 1); | |
String localName = qualifiedName; | |
if(attributePrefix != null && qualifiedName.startsWith(attributePrefix)){ | |
break; | |
} | |
String uri = Constants.EMPTY_STRING; | |
if(namespaceAware && namespaces != null){ | |
if(localName.length() > 2){ | |
int nsIndex = localName.indexOf(namespaceSeparator, 1); | |
String prefix = Constants.EMPTY_STRING; | |
if(nsIndex > -1){ | |
prefix = localName.substring(0, nsIndex); | |
} | |
uri = namespaces.resolveNamespacePrefix(prefix); | |
if(uri == null){ | |
uri = namespaces.getDefaultNamespaceURI(); | |
}else{ | |
localName = localName.substring(nsIndex + 1); | |
} | |
if(localName.equals(Constants.SCHEMA_TYPE_ATTRIBUTE) && uri != null && uri.equals(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)){ | |
break; | |
} | |
}else{ | |
uri = namespaces.getDefaultNamespaceURI(); | |
} | |
} | |
if(contentHandler instanceof XMLRootRecord || contentHandler instanceof DeferredContentHandler){ | |
//if its not namespaceAware don't report the "type" child as it is will be read by the xsi:type lookup | |
if(!namespaceAware && localName.equals(Constants.SCHEMA_TYPE_ATTRIBUTE)){ | |
break; | |
} | |
if(textWrapper != null && textWrapper.equals(localName)){ | |
parse(valueTree); | |
break; | |
} | |
}else if(contentHandler instanceof UnmarshalRecord && ((UnmarshalRecord)contentHandler).getXPathNode() != null){ | |
if(!namespaceAware && localName.equals(Constants.SCHEMA_TYPE_ATTRIBUTE) && !((UnmarshalRecord)contentHandler).getXPathNode().hasTypeChild()){ | |
break; | |
} | |
boolean isTextValue = isTextValue(localName); | |
if(isTextValue){ | |
parse(valueTree); | |
break; | |
} | |
NodeValue nv = ((UnmarshalRecord)contentHandler).getAttributeChildNodeValue(uri, localName); | |
if(attributePrefix == null && nv !=null ){ | |
break; | |
} | |
} | |
if(valueTree != null && valueTree.getType() == JSONLexer.NULL){ | |
contentHandler.setNil(true); | |
} | |
contentHandler.startElement(uri, localName, localName, attributes.setTree(valueTree, attributePrefix, namespaces, namespaceSeparator, namespaceAware)); | |
parse(valueTree); | |
contentHandler.endElement(uri, localName, localName); | |
} | |
break; | |
} | |
case JSONLexer.STRING: { | |
String string = string(tree.getChild(0).getText()); | |
contentHandler.characters(string); | |
break; | |
} | |
case JSONLexer.NUMBER: { | |
contentHandler.characters(tree.getChild(0).getText()); | |
break; | |
} | |
case JSONLexer.TRUE: { | |
contentHandler.characters(TRUE); | |
break; | |
} | |
case JSONLexer.FALSE: { | |
contentHandler.characters(FALSE); | |
break; | |
} | |
case JSONLexer.NULL: { | |
break; | |
} | |
case JSONLexer.ARRAY: { | |
Tree parentStringTree = tree.getParent().getChild(0); | |
String parentLocalName = parentStringTree.getText().substring(1, parentStringTree.getText().length() - 1); | |
if(attributePrefix != null && parentLocalName.startsWith(attributePrefix)){ | |
break; | |
} | |
String uri = Constants.EMPTY_STRING; | |
if(namespaceAware && namespaces != null){ | |
if(parentLocalName.length() > 2){ | |
int nsIndex = parentLocalName.indexOf(namespaceSeparator, 1); | |
if(nsIndex > -1){ | |
String prefix = parentLocalName.substring(0, nsIndex); | |
uri = namespaces.resolveNamespacePrefix(prefix); | |
} | |
if(uri == null){ | |
uri = namespaces.getDefaultNamespaceURI(); | |
}else{ | |
parentLocalName = parentLocalName.substring(nsIndex + 1); | |
} | |
}else{ | |
uri = namespaces.getDefaultNamespaceURI(); | |
} | |
} | |
boolean isTextValue = false; | |
int size = tree.getChildCount(); | |
if(size == 0){ | |
if(contentHandler instanceof UnmarshalRecord){ | |
isTextValue = isTextValue(parentLocalName); | |
UnmarshalRecord ur = (UnmarshalRecord)contentHandler; | |
XPathNode node = ur.getNonAttributeXPathNode(uri, parentLocalName, parentLocalName, null); | |
if(node != null){ | |
NodeValue nv = node.getNodeValue(); | |
if(nv == null && node.getTextNode() != null){ | |
nv = node.getTextNode().getUnmarshalNodeValue(); | |
} | |
if(nv != null && nv.isContainerValue()){ | |
ur.getContainerInstance(((ContainerValue)nv)); | |
} | |
} | |
} | |
} | |
startCollection(); | |
XPathFragment groupingXPathFragment = null; | |
XPathFragment itemXPathFragment = null; | |
if(contentHandler instanceof UnmarshalRecord) { | |
isTextValue = isTextValue(parentLocalName); | |
UnmarshalRecord unmarshalRecord = (UnmarshalRecord) contentHandler; | |
if(unmarshalRecord.getUnmarshaller().isWrapperAsCollectionName()) { | |
XPathNode unmarshalRecordXPathNode = unmarshalRecord.getXPathNode(); | |
if(null != unmarshalRecordXPathNode) { | |
XPathFragment currentFragment = new XPathFragment(); | |
currentFragment.setLocalName(parentLocalName); | |
currentFragment.setNamespaceURI(uri); | |
currentFragment.setNamespaceAware(namespaceAware); | |
XPathNode groupingXPathNode = unmarshalRecordXPathNode.getNonAttributeChildrenMap().get(currentFragment); | |
if(groupingXPathNode != null) { | |
if(groupingXPathNode.getUnmarshalNodeValue() instanceof CollectionGroupingElementNodeValue) { | |
groupingXPathFragment = groupingXPathNode.getXPathFragment(); | |
contentHandler.startElement(uri, parentLocalName, parentLocalName, new AttributesImpl()); | |
XPathNode itemXPathNode = groupingXPathNode.getNonAttributeChildren().get(0); | |
itemXPathFragment = itemXPathNode.getXPathFragment(); | |
} else if(groupingXPathNode.getUnmarshalNodeValue() == null) { | |
XPathNode itemXPathNode = groupingXPathNode.getNonAttributeChildren().get(0); | |
if(itemXPathNode != null) { | |
if(((MappingNodeValue)itemXPathNode.getUnmarshalNodeValue()).isContainerValue()) { | |
groupingXPathFragment = groupingXPathNode.getXPathFragment(); | |
contentHandler.startElement(uri, parentLocalName, parentLocalName, new AttributesImpl()); | |
itemXPathFragment = itemXPathNode.getXPathFragment(); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
for(int x=0; x<size; x++) { | |
CommonTree nextChildTree = (CommonTree) tree.getChild(x); | |
if(nextChildTree.getType() == JSONLexer.NULL){ | |
((UnmarshalRecord)contentHandler).setNil(true); | |
} | |
if(!isTextValue){ | |
if(null != itemXPathFragment) { | |
contentHandler.startElement(itemXPathFragment.getNamespaceURI(), itemXPathFragment.getLocalName(), itemXPathFragment.getLocalName(), attributes.setTree(nextChildTree, attributePrefix, namespaces, namespaceSeparator, namespaceAware)); | |
} else { | |
contentHandler.startElement(uri, parentLocalName, parentLocalName, attributes.setTree(nextChildTree, attributePrefix, namespaces, namespaceSeparator, namespaceAware)); | |
} | |
} | |
parse(nextChildTree); | |
if(!isTextValue){ | |
if(null != itemXPathFragment) { | |
contentHandler.endElement(uri, itemXPathFragment.getLocalName(), itemXPathFragment.getLocalName()); | |
} else { | |
contentHandler.endElement(uri, parentLocalName, parentLocalName); | |
} | |
} | |
} | |
if(null != groupingXPathFragment) { | |
contentHandler.endElement(uri, groupingXPathFragment.getLocalName(), groupingXPathFragment.getLocalName()); | |
} | |
endCollection(); | |
break; | |
} | |
default: { | |
for(int x=0, size=tree.getChildCount(); x<size; x++) { | |
parse((CommonTree) tree.getChild(x)); | |
} | |
} | |
} | |
} | |
public boolean isNullRepresentedByXsiNil(AbstractNullPolicy nullPolicy){ | |
return true; | |
} | |
private void startCollection(){ | |
isInCollection = true; | |
} | |
private void endCollection(){ | |
isInCollection = false; | |
} | |
public boolean isInCollection(){ | |
return isInCollection; | |
} | |
private boolean isTextValue(String localName){ | |
XPathNode currentNode = ((UnmarshalRecord)contentHandler).getXPathNode(); | |
if(currentNode == null){ | |
return textWrapper != null && textWrapper.equals(localName); | |
} | |
return((currentNode.getNonAttributeChildrenMap() == null | |
|| currentNode.getNonAttributeChildrenMap().size() ==0 | |
|| (currentNode.getNonAttributeChildrenMap().size() == 1 && currentNode.getTextNode() != null)) | |
&& textWrapper != null && textWrapper.equals(localName)); | |
} | |
private static String string(String string) { | |
string = string.substring(1, string.length()-1); | |
string = string.replace("\r\n", "\n"); | |
String returnString = ""; | |
int slashIndex = string.indexOf('\\'); | |
if(slashIndex == -1){ | |
return string; | |
} | |
int position = 0; | |
while(slashIndex > -1){ | |
String subString = string.substring(position, slashIndex); | |
returnString += subString; | |
position = slashIndex; | |
char nextChar = string.charAt(slashIndex + 1); | |
switch (nextChar){ | |
case 'b':{ | |
position += 2; | |
returnString += '\b'; | |
break; | |
} | |
case 'r':{ | |
position += 2; | |
returnString += '\r'; | |
break; | |
} | |
case 'f':{ | |
position += 2; | |
returnString += '\f'; | |
break; | |
} | |
case 'n':{ | |
position += 2; | |
returnString += '\n'; | |
break; | |
} | |
case 't': { | |
position += 2; | |
returnString += '\t'; | |
break; | |
} | |
case '"': { | |
position += 2; | |
returnString += '"'; | |
break; | |
} | |
case '\\':{ | |
position += 2; | |
returnString += '\\'; | |
break; | |
} | |
case '/':{ | |
position += 2; | |
returnString += '/'; | |
break; | |
} | |
case 'u':{ | |
position += 6; | |
String hexValue = string.substring(slashIndex+2, slashIndex+6); | |
returnString += Character.toString((char)Integer.parseInt(hexValue, 16)); | |
break; | |
} | |
} | |
slashIndex = string.indexOf('\\', position); | |
} | |
//If there is content after the last '\' then append it. | |
if(position < string.length()){ | |
String subString = string.substring(position, string.length()); | |
returnString += subString; | |
} | |
return returnString; | |
} | |
/** | |
* INTERNAL: | |
* @since 2.4 | |
*/ | |
@Override | |
public Object convertValueBasedOnSchemaType(Field xmlField, Object value, XMLConversionManager xmlConversionManager, AbstractUnmarshalRecord record) { | |
if (xmlField.getSchemaType() != null) { | |
if(Constants.QNAME_QNAME.equals(xmlField.getSchemaType())){ | |
String stringValue = (String)value; | |
int indexOpen = stringValue.indexOf('{'); | |
int indexClose = stringValue.indexOf('}'); | |
String uri = null; | |
String localName = null; | |
if(indexOpen > -1 && indexClose > -1){ | |
uri = stringValue.substring(indexOpen+1, indexClose); | |
localName = stringValue.substring(indexClose + 1); | |
}else{ | |
QName obj = (QName)xmlField.convertValueBasedOnSchemaType(stringValue, xmlConversionManager, record); | |
localName = obj.getLocalPart(); | |
uri = obj.getNamespaceURI(); | |
} | |
if(uri != null){ | |
return new QName(uri, localName); | |
}else{ | |
return new QName(localName); | |
} | |
}else{ | |
Class fieldType = xmlField.getType(); | |
if (fieldType == null) { | |
fieldType = xmlField.getJavaClass(xmlField.getSchemaType()); | |
} | |
return xmlConversionManager.convertObject(value, fieldType, xmlField.getSchemaType()); | |
} | |
} | |
return value; | |
} | |
/** | |
* INTERNAL: | |
* The MediaType associated with this reader | |
* @return | |
*/ | |
@Override | |
public MediaType getMediaType(){ | |
return Constants.APPLICATION_JSON; | |
} | |
private static class JSONAttributes extends IndexedAttributeList { | |
private Tree tree; | |
private String attributePrefix; | |
private char namespaceSeparator; | |
private NamespaceResolver namespaces; | |
private boolean namespaceAware; | |
public JSONAttributes setTree(Tree tree, String attributePrefix, NamespaceResolver nr, char namespaceSeparator, boolean namespaceAware) { | |
reset(); | |
this.tree = tree; | |
this.attributePrefix = attributePrefix; | |
this.namespaces = nr; | |
this.namespaceSeparator = namespaceSeparator; | |
this.namespaceAware = namespaceAware; | |
return this; | |
} | |
private void addSimpleAttribute(List attributes, String uri, String attributeLocalName,Tree childValueTree){ | |
switch(childValueTree.getType()) { | |
case JSONLexer.STRING: { | |
String stringValue = JSONReader.string(childValueTree.getChild(0).getText()); | |
attributes.add(new Attribute(uri, attributeLocalName, attributeLocalName, stringValue)); | |
break; | |
} | |
case JSONLexer.NUMBER: { | |
attributes.add(new Attribute(uri, attributeLocalName, attributeLocalName, childValueTree.getChild(0).getText())); | |
break; | |
} | |
case JSONLexer.TRUE: { | |
attributes.add(new Attribute(uri, attributeLocalName, attributeLocalName, TRUE)); | |
break; | |
} | |
case JSONLexer.FALSE: { | |
attributes.add(new Attribute(uri, attributeLocalName, attributeLocalName, FALSE)); | |
break; | |
} | |
case JSONLexer.NULL: { | |
break; | |
} | |
} | |
} | |
public int getIndex(String uri, String localName) { | |
if(null == localName) { | |
return -1; | |
} | |
int index = 0; | |
for(Attribute attribute : attributes()) { | |
if(namespaceAware){ | |
QName testQName = new QName(uri, localName); | |
if(localName.equals(attribute.getLocalName()) && uri.equals(attribute.getUri())){ | |
return index; | |
} | |
}else{ | |
if(attribute.getName().equals(localName)) { | |
return index; | |
} | |
} | |
index++; | |
} | |
return -1; | |
} | |
@Override | |
protected Attribute[] attributes() { | |
if(null == attributes) { | |
if(tree.getType() == JSONLexer.NULL){ | |
return NO_ATTRIBUTES; | |
} | |
if(tree.getType() == JSONLexer.OBJECT) { | |
ArrayList<Attribute> attributesList = new ArrayList<Attribute>(tree.getChildCount()); | |
for(int x=0; x<tree.getChildCount(); x++) { | |
Tree childTree = tree.getChild(x); | |
String attributeLocalName = childTree.getChild(0).getText().substring(1, childTree.getChild(0).getText().length() - 1); | |
if(attributePrefix != null){ | |
if(attributeLocalName.startsWith(attributePrefix)){ | |
attributeLocalName = attributeLocalName.substring(attributePrefix.length()); | |
}else{ | |
break; | |
} | |
} | |
String uri = Constants.EMPTY_STRING; | |
if(namespaceAware && namespaces != null){ | |
if(attributeLocalName.length() > 2){ | |
String prefix = Constants.EMPTY_STRING; | |
int nsIndex = attributeLocalName.indexOf(namespaceSeparator, 1); | |
if(nsIndex > -1){ | |
prefix = attributeLocalName.substring(0, nsIndex); | |
} | |
uri = namespaces.resolveNamespacePrefix(prefix); | |
if(uri == null){ | |
uri = namespaces.getDefaultNamespaceURI(); | |
}else{ | |
attributeLocalName = attributeLocalName.substring(nsIndex + 1); | |
} | |
}else{ | |
uri = namespaces.getDefaultNamespaceURI(); | |
} | |
} | |
Tree childValueTree = childTree.getChild(1); | |
if(childValueTree.getType() == JSONLexer.ARRAY){ | |
int size = childValueTree.getChildCount(); | |
if(size == 0){ | |
attributesList.add(new Attribute(uri, attributeLocalName, attributeLocalName, "")); | |
} | |
for(int y=0; y<size; y++) { | |
CommonTree nextChildTree = (CommonTree) childValueTree.getChild(y); | |
addSimpleAttribute(attributesList, uri, attributeLocalName, nextChildTree); | |
} | |
}else{ | |
addSimpleAttribute(attributesList, uri, attributeLocalName, childValueTree); | |
} | |
} | |
attributes = attributesList.toArray(new Attribute[attributesList.size()]); | |
} else { | |
attributes = NO_ATTRIBUTES; | |
} | |
} | |
return attributes; | |
} | |
} | |
/** | |
* JSONParser is a generated class and maybe regenerated. | |
* this is a subclass to throw errors that may occur instead of just logging them. | |
*/ | |
private static class ExtendedJSONParser extends JSONParser { | |
private InputSource inputSource; | |
private ErrorHandler errorHandler; | |
public ExtendedJSONParser(TokenStream input, InputSource inputSource, ErrorHandler errorHandler) { | |
super(input); | |
this.inputSource = inputSource; | |
this.errorHandler = errorHandler; | |
} | |
public void displayRecognitionError(String[] tokenNames,RecognitionException re){ | |
super.displayRecognitionError(tokenNames, re); | |
SAXParseException saxParseException = new SAXParseException(re.getLocalizedMessage(), inputSource.getPublicId(),inputSource.getSystemId(), re.line, re.index, re); | |
try { | |
errorHandler.fatalError(saxParseException); | |
} catch (SAXException e) { | |
throw new SAXExceptionWrapper(e); | |
} | |
} | |
} | |
//Runtime exception to wrap a SAXException | |
private static class SAXExceptionWrapper extends RuntimeException { | |
SAXExceptionWrapper(SAXException e){ | |
super(e); | |
} | |
public SAXException getCause() { | |
return (SAXException)super.getCause(); | |
} | |
} | |
} |