com.sun.jersey.json.impl.reader.Jackson2StaxReader Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.jersey.json.impl.reader;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.json.impl.ImplMessages;
import com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.codehaus.jackson.JsonParser;
/**
*
* @author japod
*/
public class Jackson2StaxReader implements XMLStreamReader {
private static class ProcessingInfo {
QName name;
boolean isArray;
boolean isFirstElement;
ProcessingInfo(QName name, boolean isArray, boolean isFirstElement) {
this.name = name;
this.isArray = isArray;
this.isFirstElement = isFirstElement;
}
}
JsonParser parser;
final Queue eventQueue = new LinkedList();
final List processingStack = new ArrayList();
final JsonNamespaceContext namespaceContext = new JsonNamespaceContext();
private boolean properJAXBVersion = true;
private final boolean attrsWithPrefix;
final Collection elemsExpected = new HashSet();
final Map qNamesOfExpElems = new HashMap();
final Collection attrsExpected = new HashSet();
final Map qNamesOfExpAttrs = new HashMap();
static T pop(List stack) {
return stack.remove(stack.size() - 1);
}
static T peek(List stack) {
return (stack.size() > 0) ? stack.get(stack.size() - 1) : null;
}
static T peek2nd(List stack) {
return (stack.size() > 1) ? stack.get(stack.size() - 2) : null;
}
public Jackson2StaxReader(JsonParser parser) throws XMLStreamException {
this(parser, JSONConfiguration.DEFAULT);
}
public Jackson2StaxReader(JsonParser parser, JSONConfiguration config) throws XMLStreamException {
this.attrsWithPrefix = config.isUsingPrefixesAtNaturalAttributes();
this.parser = parser;
try {
readNext();
} catch (IOException ex) {
Logger.getLogger(Jackson2StaxReader.class.getName()).log(Level.SEVERE, null, ex);
throw new XMLStreamException(ex);
}
}
public Object getProperty(String name) throws IllegalArgumentException {
throw new UnsupportedOperationException("Not supported yet.");
}
private void readNext() throws IOException {
readNext(false);
}
final static Collection valueTokens = new HashSet() {
{
add(org.codehaus.jackson.JsonToken.VALUE_FALSE);
add(org.codehaus.jackson.JsonToken.VALUE_TRUE);
add(org.codehaus.jackson.JsonToken.VALUE_NULL);
add(org.codehaus.jackson.JsonToken.VALUE_STRING);
add(org.codehaus.jackson.JsonToken.VALUE_NUMBER_FLOAT);
add(org.codehaus.jackson.JsonToken.VALUE_NUMBER_INT);
}
};
private QName getQNameForTagLocName(final String localName) {
return getQNameForLocName(localName, qNamesOfExpElems);
}
private QName getQNameForLocName(final String localName, final Map qNamesMap) {
final QName result = qNamesMap.get(localName);
if (result != null) {
return result;
} else {
return new QName(localName);
}
}
private void readNext(boolean lookingForAttributes) throws IOException {
if (!lookingForAttributes) {
eventQueue.poll();
}
while (eventQueue.isEmpty() || lookingForAttributes) {
org.codehaus.jackson.JsonToken jtok;
// TODO: ask Jackson to take care of DOS
while (true) {
parser.nextToken();
jtok = parser.getCurrentToken();
final ProcessingInfo pi = peek(processingStack);
switch (jtok) {
case FIELD_NAME:
// start tag
String currentName = parser.getCurrentName();
if (attrsWithPrefix && currentName.startsWith("@")) {
currentName = currentName.substring(1);
}
boolean currentIsAttribute = !("$".equals(currentName)) && properJAXBVersion ? attrsExpected.contains(currentName) : !elemsExpected.contains(currentName);
if (lookingForAttributes && currentIsAttribute) {
parser.nextToken();
if (valueTokens.contains(parser.getCurrentToken())) {
eventQueue.peek().addAttribute(getQNameForLocName(currentName, qNamesOfExpAttrs), parser.getText());
} else {
System.out.println(String.format("CurrentName=%s", currentName));
throw new IOException("Not an attribute, expected primitive value!");
}
} else { // non attribute
lookingForAttributes = false; // stop seeking attributes
if (!("$".equals(currentName))) {
final QName currentQName = getQNameForTagLocName(currentName);
eventQueue.add(new StartElementEvent(currentQName, new StaxLocation(parser.getCurrentLocation())));
processingStack.add(new ProcessingInfo(currentQName, false, true));
return;
} else {
parser.nextToken();
if (valueTokens.contains(parser.getCurrentToken())) {
eventQueue.add(new CharactersEvent(parser.getText(), new StaxLocation(parser.getCurrentLocation())));
return;
} else {
throw new IOException("Not a xml value, expected primitive value!");
}
}
}
break;
case START_OBJECT:
if (pi == null) {
eventQueue.add(new StartDocumentEvent(new StaxLocation(0, 0, 0)));
return;
}
if (pi.isArray && !pi.isFirstElement) {
eventQueue.add(new StartElementEvent(pi.name, new StaxLocation(parser.getCurrentLocation())));
return;
} else {
pi.isFirstElement = false;
}
break;
case END_OBJECT:
lookingForAttributes = false;
// end tag
eventQueue.add(new EndElementEvent(pi.name, new StaxLocation(parser.getCurrentLocation())));
if (!pi.isArray) {
pop(processingStack);
}
if (processingStack.isEmpty()) {
eventQueue.add(new EndDocumentEvent(new StaxLocation(parser.getCurrentLocation())));
}
return;
case VALUE_FALSE:
case VALUE_NULL:
case VALUE_NUMBER_FLOAT:
case VALUE_NUMBER_INT:
case VALUE_TRUE:
case VALUE_STRING:
if (!pi.isFirstElement) {
eventQueue.add(new StartElementEvent(pi.name, new StaxLocation(parser.getCurrentLocation())));
} else {
pi.isFirstElement = false;
}
if (jtok != jtok.VALUE_NULL) {
eventQueue.add(new CharactersEvent(parser.getText(), new StaxLocation(parser.getCurrentLocation())));
}
eventQueue.add(new EndElementEvent(pi.name, new StaxLocation(parser.getCurrentLocation())));
if (!pi.isArray) {
pop(processingStack);
}
if (processingStack.isEmpty()) {
eventQueue.add(new EndDocumentEvent(new StaxLocation(parser.getCurrentLocation())));
}
lookingForAttributes = false;
return;
case START_ARRAY:
peek(processingStack).isArray = true;
break;
case END_ARRAY :
pop(processingStack);
lookingForAttributes = false;
}
}
}
}
public void require(int arg0, String arg1, String arg2) throws XMLStreamException {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getElementText() throws XMLStreamException {
throw new UnsupportedOperationException("Not supported yet.");
}
public int next() throws XMLStreamException {
try {
readNext();
return eventQueue.peek().getEventType();
} catch (IOException ex) {
Logger.getLogger(JsonXmlStreamReader.class.getName()).log(Level.SEVERE, null, ex);
throw new XMLStreamException(ex);
}
}
public int nextTag() throws XMLStreamException {
int eventType = next();
while ((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace
|| (eventType == XMLStreamConstants.CDATA && isWhiteSpace()) // skip whitespace
|| eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) {
eventType = next();
}
if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
throw new XMLStreamException("expected start or end tag", getLocation());
}
return eventType;
}
public boolean hasNext() throws XMLStreamException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void close() throws XMLStreamException {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getNamespaceURI(
String arg0) {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean isStartElement() {
return eventQueue.peek().isStartElement();
}
public boolean isEndElement() {
return eventQueue.peek().isEndElement();
}
public boolean isCharacters() {
return eventQueue.peek().isCharacters();
}
public boolean isWhiteSpace() {
return false;
}
public String getAttributeValue(
String namespaceURI, String localName) {
return eventQueue.peek().getAttributeValue(namespaceURI, localName);
}
public int getAttributeCount() {
try {
if (!eventQueue.peek().attributesChecked) {
elemsExpected.clear();
qNamesOfExpElems.clear();
attrsExpected.clear();
qNamesOfExpAttrs.clear();
final UnmarshallingContext uctx = UnmarshallingContext.getInstance();
if (uctx != null) {
try {
Collection currExpElems = uctx.getCurrentExpectedElements();
for (QName n : currExpElems) {
String nu = n.getNamespaceURI();
if (nu != null && (nu.equals("\u0000"))) {
elemsExpected.add("$");
qNamesOfExpElems.put("$", null);
} else {
elemsExpected.add(n.getLocalPart());
qNamesOfExpElems.put(n.getLocalPart(), n);
}
}
} catch (NullPointerException npe) {
// TODO: need to check what could be done in JAXB in order to prevent the npe
// thrown from com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext#1206
}
if (properJAXBVersion) {
try {
Collection currExpAttrs = uctx.getCurrentExpectedAttributes();
for (QName n : currExpAttrs) {
attrsExpected.add(n.getLocalPart());
qNamesOfExpAttrs.put(n.getLocalPart(), n);
}
} catch (NullPointerException npe) {
// thrown from com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext
} catch (NoSuchMethodError nsme) {
// thrown when JAXB version is less than 2.1.12
properJAXBVersion = false;
Logger.getLogger(Jackson2StaxReader.class.getName()).log(Level.SEVERE, ImplMessages.ERROR_JAXB_RI_2_1_12_MISSING(), nsme);
}
}
}
readNext(true);
eventQueue.peek().attributesChecked = true;
}
} catch (IOException ex) {
Logger.getLogger(Jackson2StaxReader.class.getName()).log(Level.SEVERE, null, ex);
}
return eventQueue.peek().getAttributeCount();
}
public QName getAttributeName(
int index) {
return eventQueue.peek().getAttributeName(index);
}
public String getAttributeNamespace(
int index) {
return eventQueue.peek().getAttributeNamespace(index);
}
public String getAttributeLocalName(
int index) {
return eventQueue.peek().getAttributeLocalName(index);
}
public String getAttributePrefix(
int index) {
return eventQueue.peek().getAttributePrefix(index);
}
public String getAttributeType(
int index) {
return eventQueue.peek().getAttributeType(index);
}
public String getAttributeValue(
int index) {
return eventQueue.peek().getAttributeValue(index);
}
public boolean isAttributeSpecified(int index) {
return eventQueue.peek().isAttributeSpecified(index);
}
public int getNamespaceCount() {
return this.namespaceContext.getNamespaceCount();
}
public String getNamespacePrefix(int idx) {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getNamespaceURI(int idx) {
throw new UnsupportedOperationException("Not supported yet.");
}
public NamespaceContext getNamespaceContext() {
return this.namespaceContext;
}
public int getEventType() {
return eventQueue.peek().getEventType();
}
public String getText() {
return eventQueue.peek().getText();
}
public char[] getTextCharacters() {
return eventQueue.peek().getTextCharacters();
}
public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException {
return eventQueue.peek().getTextCharacters(sourceStart, target, targetStart, length);
}
public int getTextStart() {
return eventQueue.peek().getTextStart();
}
public int getTextLength() {
return eventQueue.peek().getTextLength();
}
public String getEncoding() {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean hasText() {
throw new UnsupportedOperationException("Not supported yet.");
}
public Location getLocation() {
return eventQueue.peek().getLocation();
}
public QName getName() {
return eventQueue.peek().getName();
}
public String getLocalName() {
return eventQueue.peek().getLocalName();
}
public boolean hasName() {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getNamespaceURI() {
return eventQueue.peek().getName().getNamespaceURI();
}
public String getPrefix() {
return eventQueue.peek().getPrefix();
}
public String getVersion() {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean isStandalone() {
throw new UnsupportedOperationException("Not supported yet.");
}
public boolean standaloneSet() {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getCharacterEncodingScheme() {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getPITarget() {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getPIData() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy