Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.cxf.jaxrs.provider.AbstractJAXBProvider Maven / Gradle / Ivy
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.jaxrs.provider;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.logging.Logger;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.validation.Schema;
import org.apache.cxf.common.i18n.BundleUtils;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.PackageUtils;
import org.apache.cxf.common.util.ReflectionInvokationHandler;
import org.apache.cxf.jaxb.JAXBBeanInfo;
import org.apache.cxf.jaxb.JAXBContextProxy;
import org.apache.cxf.jaxb.JAXBUtils;
import org.apache.cxf.jaxrs.ext.MessageContext;
import org.apache.cxf.jaxrs.utils.AnnotationUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
import org.apache.cxf.jaxrs.utils.JAXRSUtils;
import org.apache.cxf.jaxrs.utils.schemas.SchemaHandler;
import org.apache.cxf.staxutils.DelegatingXMLStreamWriter;
import org.apache.cxf.staxutils.DepthXMLStreamReader;
import org.apache.cxf.staxutils.StaxStreamFilter;
import org.apache.cxf.staxutils.StaxUtils;
public abstract class AbstractJAXBProvider extends AbstractConfigurableProvider
implements MessageBodyReader, MessageBodyWriter {
protected static final ResourceBundle BUNDLE = BundleUtils.getBundle(AbstractJAXBProvider.class);
private static final Logger LOG = LogUtils.getL7dLogger(AbstractJAXBProvider.class);
private static final String JAXB_DEFAULT_NAMESPACE = "##default";
private static final String JAXB_DEFAULT_NAME = "##default";
private static Map packageContexts = new HashMap();
private static Map, JAXBContext> classContexts = new HashMap, JAXBContext>();
protected Set> collectionContextClasses = new HashSet>();
protected JAXBContext collectionContext;
protected Map jaxbElementClassMap;
protected boolean unmarshalAsJaxbElement;
protected boolean marshalAsJaxbElement;
protected Map outElementsMap;
protected Map outAppendMap;
protected List outDropElements;
protected List inDropElements;
protected Map inElementsMap;
protected Map inAppendMap;
private boolean attributesToElements;
private MessageContext mc;
private Schema schema;
private String collectionWrapperName;
private Map collectionWrapperMap;
private List jaxbElementClassNames;
private Map cProperties;
private Map uProperties;
private boolean skipJaxbChecks;
public void setContextProperties(Map contextProperties) {
cProperties = contextProperties;
}
public void setUnmarshallerProperties(Map unmarshalProperties) {
uProperties = unmarshalProperties;
}
public void setUnmarshallAsJaxbElement(boolean value) {
unmarshalAsJaxbElement = value;
}
public void setMarshallAsJaxbElement(boolean value) {
marshalAsJaxbElement = value;
}
public void setJaxbElementClassNames(List names) {
jaxbElementClassNames = names;
}
public void setJaxbElementClassMap(Map map) {
jaxbElementClassMap = map;
}
protected void checkContentLength() {
if (mc != null) {
List values = mc.getHttpHeaders().getRequestHeader(HttpHeaders.CONTENT_LENGTH);
if (values.size() == 1 && "0".equals(values.get(0))) {
String message = new org.apache.cxf.common.i18n.Message("EMPTY_BODY", BUNDLE).toString();
LOG.warning(message);
throw new WebApplicationException(400);
}
}
}
@SuppressWarnings("unchecked")
protected Object convertToJaxbElementIfNeeded(Object obj, Class> cls, Type genericType)
throws Exception {
QName name = null;
if (jaxbElementClassNames != null && jaxbElementClassNames.contains(cls.getName())
|| jaxbElementClassMap != null && jaxbElementClassMap.containsKey(cls.getName())) {
if (jaxbElementClassMap != null) {
name = JAXRSUtils.convertStringToQName(jaxbElementClassMap.get(cls.getName()));
} else {
name = getJaxbQName(cls, genericType, obj, false);
}
}
if (name == null && marshalAsJaxbElement) {
name = JAXRSUtils.convertStringToQName(cls.getSimpleName());
}
if (name != null) {
return new JAXBElement(name, cls, null, obj);
}
return obj;
}
public void setCollectionWrapperName(String wName) {
collectionWrapperName = wName;
}
public void setCollectionWrapperMap(Map map) {
collectionWrapperMap = map;
}
protected void setContext(MessageContext context) {
mc = context;
}
public boolean isWriteable(Class> type, Type genericType, Annotation[] anns, MediaType mt) {
if (InjectionUtils.isSupportedCollectionOrArray(type)) {
type = InjectionUtils.getActualType(genericType);
if (type == null) {
return false;
}
}
return unmarshalAsJaxbElement || isSupported(type, genericType, anns);
}
protected JAXBContext getCollectionContext(Class> type) throws JAXBException {
synchronized (collectionContextClasses) {
if (!collectionContextClasses.contains(type)) {
collectionContextClasses.add(CollectionWrapper.class);
collectionContextClasses.add(type);
}
collectionContext = JAXBContext.newInstance(collectionContextClasses.toArray(new Class[]{}),
cProperties);
return collectionContext;
}
}
protected QName getCollectionWrapperQName(Class> cls, Type type, Object object, boolean pluralName)
throws Exception {
String name = getCollectionWrapperName(cls);
if (name == null) {
return getJaxbQName(cls, type, object, pluralName);
}
return JAXRSUtils.convertStringToQName(name);
}
private String getCollectionWrapperName(Class> cls) {
if (collectionWrapperName != null) {
return collectionWrapperName;
}
if (collectionWrapperMap != null) {
return collectionWrapperMap.get(cls.getName());
}
return null;
}
protected QName getJaxbQName(Class> cls, Type type, Object object, boolean pluralName)
throws Exception {
if (cls == JAXBElement.class) {
return object != null ? ((JAXBElement)object).getName() : null;
}
XmlRootElement root = cls.getAnnotation(XmlRootElement.class);
QName qname = null;
if (root != null) {
String namespace = getNamespace(root.namespace());
if ("".equals(namespace)) {
String packageNs = JAXBUtils.getPackageNamespace(cls);
if (packageNs != null) {
namespace = getNamespace(packageNs);
}
}
String name = getLocalName(root.name(), cls.getSimpleName(), pluralName);
return new QName(namespace, name);
} else {
JAXBContext context = getJAXBContext(cls, type);
JAXBContextProxy proxy = ReflectionInvokationHandler.createProxyWrapper(context,
JAXBContextProxy.class);
JAXBBeanInfo info = JAXBUtils.getBeanInfo(proxy, cls);
if (info != null) {
try {
Object instance = object == null ? cls.newInstance() : object;
String name = getLocalName(info.getElementLocalName(instance), cls.getSimpleName(),
pluralName);
String namespace = getNamespace(info.getElementNamespaceURI(instance));
return new QName(namespace, name);
} catch (Exception ex) {
// ignore
}
}
}
return qname;
}
private String getLocalName(String name, String clsName, boolean pluralName) {
if (JAXB_DEFAULT_NAME.equals(name)) {
name = clsName;
if (name.length() > 1) {
name = name.substring(0, 1).toLowerCase() + name.substring(1);
} else {
name = name.toLowerCase();
}
}
if (pluralName) {
name += 's';
}
return name;
}
private String getNamespace(String namespace) {
if (JAXB_DEFAULT_NAMESPACE.equals(namespace)) {
return "";
}
return namespace;
}
public boolean isReadable(Class> type, Type genericType, Annotation[] anns, MediaType mt) {
return marshalAsJaxbElement || isSupported(type, genericType, anns);
}
public void setSchemaLocations(List locations) {
schema = SchemaHandler.createSchema(locations, getBus());
}
public void setSchema(Schema s) {
schema = s;
}
public long getSize(Object o, Class> type, Type genericType, Annotation[] annotations, MediaType mt) {
return -1;
}
protected MessageContext getContext() {
return mc;
}
@SuppressWarnings("unchecked")
protected JAXBContext getJAXBContext(Class> type, Type genericType) throws JAXBException {
if (mc != null) {
ContextResolver resolver =
mc.getResolver(ContextResolver.class, JAXBContext.class);
if (resolver != null) {
JAXBContext customContext = resolver.getContext(type);
if (customContext != null) {
return customContext;
}
}
}
synchronized (classContexts) {
JAXBContext context = classContexts.get(type);
if (context != null) {
return context;
}
}
JAXBContext context = getPackageContext(type);
if (context == null && type != genericType) {
context = getPackageContext(InjectionUtils.getActualType(genericType));
}
return context != null ? context : getClassContext(type);
}
public JAXBContext getClassContext(Class> type) throws JAXBException {
synchronized (classContexts) {
JAXBContext context = classContexts.get(type);
if (context == null) {
context = JAXBContext.newInstance(new Class[]{type}, cProperties);
classContexts.put(type, context);
}
return context;
}
}
public JAXBContext getPackageContext(Class> type) {
if (type == null || type == JAXBElement.class) {
return null;
}
synchronized (packageContexts) {
String packageName = PackageUtils.getPackageName(type);
JAXBContext context = packageContexts.get(packageName);
if (context == null) {
try {
context = JAXBContext.newInstance(packageName, type.getClassLoader(), cProperties);
packageContexts.put(packageName, context);
} catch (JAXBException ex) {
LOG.fine("Error creating a JAXBContext using ObjectFactory : "
+ ex.getMessage());
return null;
}
}
return context;
}
}
protected boolean isSupported(Class> type, Type genericType, Annotation[] anns) {
if (jaxbElementClassMap != null && jaxbElementClassMap.containsKey(type.getName())
|| isSkipJaxbChecks()) {
return true;
}
return type.getAnnotation(XmlRootElement.class) != null
|| JAXBElement.class.isAssignableFrom(type)
|| objectFactoryForClass(type)
|| (type != genericType && objectFactoryForType(genericType))
|| getAdapter(type, anns) != null
|| type.getResource("jaxb.index") != null;
}
protected boolean objectFactoryForClass(Class> type) {
try {
return type.getClassLoader().loadClass(PackageUtils.getPackageName(type)
+ ".ObjectFactory") != null;
} catch (Exception ex) {
return false;
}
}
private boolean objectFactoryForType(Type genericType) {
return objectFactoryForClass(InjectionUtils.getActualType(genericType));
}
protected Unmarshaller createUnmarshaller(Class> cls, Type genericType)
throws JAXBException {
return createUnmarshaller(cls, genericType, false);
}
protected Unmarshaller createUnmarshaller(Class> cls, Type genericType, boolean isCollection)
throws JAXBException {
JAXBContext context = isCollection ? getCollectionContext(cls)
: getJAXBContext(cls, genericType);
Unmarshaller unmarshaller = context.createUnmarshaller();
if (schema != null) {
unmarshaller.setSchema(schema);
}
if (uProperties != null) {
for (Map.Entry entry : uProperties.entrySet()) {
unmarshaller.setProperty(entry.getKey(), entry.getValue());
}
}
return unmarshaller;
}
protected Marshaller createMarshaller(Object obj, Class> cls, Type genericType, String enc)
throws JAXBException {
Class> objClazz = JAXBElement.class.isAssignableFrom(cls)
? ((JAXBElement)obj).getDeclaredType() : cls;
JAXBContext context = getJAXBContext(objClazz, genericType);
Marshaller marshaller = context.createMarshaller();
if (enc != null) {
marshaller.setProperty(Marshaller.JAXB_ENCODING, enc);
}
return marshaller;
}
protected Class> getActualType(Class> type, Type genericType, Annotation[] anns) {
Class> theType = null;
if (JAXBElement.class.isAssignableFrom(type)) {
theType = InjectionUtils.getActualType(genericType);
} else {
theType = type;
}
XmlJavaTypeAdapter adapter = getAdapter(theType, anns);
if (adapter != null) {
if (adapter.type() != XmlJavaTypeAdapter.DEFAULT.class) {
theType = adapter.type();
} else {
Type[] types = InjectionUtils.getActualTypes(adapter.value().getGenericSuperclass());
if (types != null && types.length == 2) {
theType = (Class)types[0];
}
}
}
return theType;
}
@SuppressWarnings("unchecked")
protected Object checkAdapter(Object obj, Class> cls, Annotation[] anns, boolean marshal) {
XmlJavaTypeAdapter typeAdapter = getAdapter(obj.getClass(), anns);
if (typeAdapter != null) {
try {
XmlAdapter xmlAdapter = typeAdapter.value().newInstance();
if (marshal) {
return xmlAdapter.marshal(obj);
} else {
return xmlAdapter.unmarshal(obj);
}
} catch (Exception ex) {
LOG.warning("Problem using the XmlJavaTypeAdapter");
ex.printStackTrace();
}
}
return obj;
}
protected XmlJavaTypeAdapter getAdapter(Class> objectClass, Annotation[] anns) {
XmlJavaTypeAdapter typeAdapter = AnnotationUtils.getAnnotation(anns, XmlJavaTypeAdapter.class);
if (typeAdapter == null) {
typeAdapter = objectClass.getAnnotation(XmlJavaTypeAdapter.class);
if (typeAdapter == null) {
// lets just try the 1st interface for now
Class>[] interfaces = objectClass.getInterfaces();
typeAdapter = interfaces.length > 0
? interfaces[0].getAnnotation(XmlJavaTypeAdapter.class) : null;
}
}
return typeAdapter;
}
protected Schema getSchema() {
return schema;
}
static void clearContexts() {
classContexts.clear();
packageContexts.clear();
}
protected static void handleJAXBException(JAXBException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
LOG.warning(sw.toString());
StringBuilder sb = new StringBuilder();
if (e.getMessage() != null) {
sb.append(e.getMessage()).append(". ");
}
if (e.getCause() != null && e.getCause().getMessage() != null) {
sb.append(e.getCause().getMessage()).append(". ");
}
if (e.getLinkedException() != null && e.getLinkedException().getMessage() != null) {
sb.append(e.getLinkedException().getMessage()).append(". ");
}
Throwable t = e.getLinkedException() != null
? e.getLinkedException() : e.getCause() != null ? e.getCause() : e;
String message = new org.apache.cxf.common.i18n.Message("JAXB_EXCEPTION",
BUNDLE, sb.toString()).toString();
Response r = Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.type(MediaType.TEXT_PLAIN).entity(message).build();
throw new WebApplicationException(t, r);
}
public void setOutTransformElements(Map outElements) {
this.outElementsMap = outElements;
}
public void setInAppendElements(Map inElements) {
this.inAppendMap = inElements;
}
public void setInTransformElements(Map inElements) {
this.inElementsMap = inElements;
}
public void setOutAppendElements(Map map) {
this.outAppendMap = map;
}
public void setOutDropElements(List dropElementsSet) {
this.outDropElements = dropElementsSet;
}
public void setInDropElements(List dropElementsSet) {
this.inDropElements = dropElementsSet;
}
protected static Set convertToSetOfQNames(List dropEls) {
Set dropElements = Collections.emptySet();
if (dropEls != null) {
dropElements = new LinkedHashSet(dropEls.size());
for (String val : dropEls) {
dropElements.add(JAXRSUtils.convertStringToQName(val));
}
}
return dropElements;
}
protected XMLStreamReader createTransformReaderIfNeeded(XMLStreamReader reader, InputStream is) {
if (inDropElements != null) {
Set dropElements = convertToSetOfQNames(inDropElements);
reader = StaxUtils.createFilteredReader(createNewReaderIfNeeded(reader, is),
new StaxStreamFilter(dropElements.toArray(new QName[]{})));
}
if (inElementsMap != null || inAppendMap != null) {
reader = new InTransformReader(createNewReaderIfNeeded(reader, is),
inElementsMap, inAppendMap);
}
return reader;
}
protected XMLStreamWriter createTransformWriterIfNeeded(XMLStreamWriter writer,
OutputStream os) {
if (outElementsMap != null || outDropElements != null
|| outAppendMap != null || attributesToElements) {
writer = createNewWriterIfNeeded(writer, os);
writer = new OutTransformWriter(writer, outElementsMap, outAppendMap,
outDropElements, attributesToElements);
}
return writer;
}
protected XMLStreamReader createNewReaderIfNeeded(XMLStreamReader reader, InputStream is) {
return reader == null ? StaxUtils.createXMLStreamReader(is) : reader;
}
protected XMLStreamWriter createNewWriterIfNeeded(XMLStreamWriter writer, OutputStream os) {
return writer == null ? StaxUtils.createXMLStreamWriter(os) : writer;
}
protected static void convertToQNamesMap(Map map,
QNamesMap elementsMap,
Map nsMap) {
if (map != null) {
for (Map.Entry entry : map.entrySet()) {
QName lname = JAXRSUtils.convertStringToQName(entry.getKey());
QName rname = JAXRSUtils.convertStringToQName(entry.getValue());
elementsMap.put(lname, rname);
if (nsMap != null) {
nsMap.put(lname.getNamespaceURI(), rname.getNamespaceURI());
}
}
}
}
protected static void convertToMapOfQNames(Map map,
Map elementsMap) {
if (map != null) {
for (Map.Entry entry : map.entrySet()) {
QName lname = JAXRSUtils.convertStringToQName(entry.getKey());
QName rname = JAXRSUtils.convertStringToQName(entry.getValue());
elementsMap.put(lname, rname);
}
}
}
public void setAttributesToElements(boolean value) {
this.attributesToElements = value;
}
public void setSkipJaxbChecks(boolean skipJaxbChecks) {
this.skipJaxbChecks = skipJaxbChecks;
}
public boolean isSkipJaxbChecks() {
return skipJaxbChecks;
}
@XmlRootElement
protected static class CollectionWrapper {
@XmlAnyElement(lax = true)
private List> l;
public void setList(List> list) {
l = list;
}
public List> getList() {
if (l == null) {
l = new ArrayList();
}
return l;
}
@SuppressWarnings("unchecked")
public Object getCollectionOrArray(Class type, Class> origType) {
List> theList = getList();
if (theList.size() > 0) {
Object first = theList.get(0);
if (first instanceof JAXBElement && !JAXBElement.class.isAssignableFrom(type)) {
List newList = new ArrayList(theList.size());
for (Object o : theList) {
newList.add(((JAXBElement)o).getValue());
}
theList = newList;
}
}
if (origType.isArray()) {
T[] values = (T[])Array.newInstance(type, theList.size());
for (int i = 0; i < theList.size(); i++) {
values[i] = (T)theList.get(i);
}
return values;
} else if (origType == Set.class) {
return new HashSet(theList);
} else {
return theList;
}
}
}
protected static class OutTransformWriter extends DelegatingXMLStreamWriter {
private QNamesMap elementsMap;
private Map appendMap = new HashMap(5);
private Map nsMap = new HashMap(5);
private Set prefixes = new HashSet(2);
private Set writtenUris = new HashSet(2);
private Set dropElements;
private List droppingIndexes = new LinkedList();
private List appendedElements = new LinkedList();
private List appendedIndexes = new LinkedList();
private int currentDepth;
private boolean attributesToElements;
public OutTransformWriter(XMLStreamWriter writer,
Map outMap,
Map append,
List dropEls,
boolean attributesToElements) {
super(writer);
elementsMap = new QNamesMap(outMap == null ? 0 : outMap.size());
convertToQNamesMap(outMap, elementsMap, nsMap);
convertToMapOfQNames(append, appendMap);
dropElements = convertToSetOfQNames(dropEls);
this.attributesToElements = attributesToElements;
}
@Override
public void writeNamespace(String prefix, String uri) throws XMLStreamException {
if (matchesDropped()) {
return;
}
if (writtenUris.contains(uri)) {
return;
}
String value = nsMap.get(uri);
if (value != null && value.length() == 0) {
return;
}
super.writeNamespace(prefix, value != null ? value : uri);
}
@Override
public void writeStartElement(String prefix, String local, String uri) throws XMLStreamException {
currentDepth++;
QName currentQName = new QName(uri, local);
QName appendQName = appendMap.get(currentQName);
if (appendQName != null && !appendedElements.contains(appendQName)) {
currentDepth++;
String theprefix = uri.equals(appendQName.getNamespaceURI()) ? prefix : "";
write(new QName(appendQName.getNamespaceURI(), appendQName.getLocalPart(), theprefix));
if (theprefix.length() > 0) {
super.writeNamespace(theprefix, uri);
writtenUris.add(uri);
}
appendedElements.add(appendQName);
appendedIndexes.add(currentDepth - 1);
}
if (dropElements.contains(currentQName)) {
droppingIndexes.add(currentDepth - 1);
return;
}
write(new QName(uri, local, prefix));
}
@Override
public void writeEndElement() throws XMLStreamException {
--currentDepth;
if (indexRemoved(droppingIndexes)) {
return;
}
super.writeEndElement();
if (indexRemoved(appendedIndexes)) {
super.writeEndElement();
}
}
@Override
public void writeCharacters(String text) throws XMLStreamException {
if (matchesDropped()) {
return;
}
super.writeCharacters(text);
}
private void write(QName qname) throws XMLStreamException {
QName name = elementsMap.get(qname);
if (name == null) {
name = qname;
}
boolean writeNs = false;
String prefix = "";
if (name.getNamespaceURI().length() > 0) {
if (qname.getPrefix().length() == 0) {
prefix = findUniquePrefix();
writeNs = true;
} else {
prefix = qname.getPrefix();
prefixes.add(prefix);
}
prefixes.add(prefix);
}
super.writeStartElement(prefix, name.getLocalPart(), name.getNamespaceURI());
if (writeNs) {
this.writeNamespace(prefix, name.getNamespaceURI());
}
}
private String findUniquePrefix() {
int i = 0;
while (true) {
if (!prefixes.contains("ps" + ++i)) {
return "ps" + i;
}
}
}
private boolean matchesDropped() {
int size = droppingIndexes.size();
if (size > 0 && droppingIndexes.get(size - 1) == currentDepth - 1) {
return true;
}
return false;
}
private boolean indexRemoved(List indexes) {
int size = indexes.size();
if (size > 0 && indexes.get(size - 1) == currentDepth) {
indexes.remove(size - 1);
return true;
}
return false;
}
@Override
public NamespaceContext getNamespaceContext() {
return new DelegatingNamespaceContext(super.getNamespaceContext(), nsMap);
}
@Override
public void writeAttribute(String uri, String local, String value) throws XMLStreamException {
if (!attributesToElements) {
super.writeAttribute(uri, local, value);
} else {
writeAttributeAsElement(uri, local, value);
}
}
@Override
public void writeAttribute(String local, String value) throws XMLStreamException {
if (!attributesToElements) {
super.writeAttribute(local, value);
} else {
writeAttributeAsElement("", local, value);
}
}
private void writeAttributeAsElement(String uri, String local, String value)
throws XMLStreamException {
this.writeStartElement(uri, local);
this.writeCharacters(value);
this.writeEndElement();
}
}
private static class QNamesMap {
private QName[] keys;
private QName[] values;
private int index;
public QNamesMap(int size) {
keys = new QName[size];
values = new QName[size];
}
public void put(QName key, QName value) {
keys[index] = key;
values[index] = value;
index++;
}
public QName get(QName key) {
for (int i = 0; i < keys.length; i++) {
if (keys[i].getNamespaceURI().equals(key.getNamespaceURI())) {
if (keys[i].getLocalPart().equals(key.getLocalPart())) {
return values[i];
} else if ("*".equals(keys[i].getLocalPart())) {
// assume it is something like {somens}* : *
return "*".equals(values[i]) ? new QName(key.getLocalPart())
: new QName(values[i].getNamespaceURI(), key.getLocalPart());
}
}
}
return null;
}
}
protected static class InTransformReader extends DepthXMLStreamReader {
private static final String INTERN_NAMES = "org.codehaus.stax2.internNames";
private static final String INTERN_NS = "org.codehaus.stax2.internNsUris";
private QNamesMap inElementsMap;
private Map inAppendMap = new HashMap(5);
private Map nsMap = new HashMap(5);
private QName currentQName;
private QName previousQName;
private int previousDepth = -1;
public InTransformReader(XMLStreamReader reader,
Map inMap,
Map appendMap) {
super(reader);
inElementsMap = new QNamesMap(inMap == null ? 0 : inMap.size());
convertToQNamesMap(inMap, inElementsMap, nsMap);
convertToMapOfQNames(appendMap, inAppendMap);
}
public int next() throws XMLStreamException {
if (currentQName != null) {
return XMLStreamConstants.START_ELEMENT;
} else if (previousDepth != -1 && previousDepth == getDepth() + 1) {
previousDepth = -1;
return XMLStreamConstants.END_ELEMENT;
} else {
return super.next();
}
}
public Object getProperty(String name) throws IllegalArgumentException {
if (INTERN_NAMES.equals(name) || INTERN_NS.equals(name)) {
return Boolean.FALSE;
}
return super.getProperty(name);
}
public String getLocalName() {
QName cQName = getCurrentName();
if (cQName != null) {
String name = cQName.getLocalPart();
resetCurrentQName();
return name;
}
return super.getLocalName();
}
private QName getCurrentName() {
return currentQName != null ? currentQName
: previousQName != null ? previousQName : null;
}
private void resetCurrentQName() {
currentQName = previousQName;
previousQName = null;
}
public NamespaceContext getNamespaceContext() {
return new DelegatingNamespaceContext(super.getNamespaceContext(), nsMap);
}
public String getNamespaceURI() {
QName theName = readCurrentElement();
QName appendQName = inAppendMap.remove(theName);
if (appendQName != null) {
previousDepth = getDepth();
previousQName = theName;
currentQName = appendQName;
return currentQName.getNamespaceURI();
}
QName expected = inElementsMap.get(theName);
if (expected == null) {
return theName.getNamespaceURI();
}
currentQName = expected;
return currentQName.getNamespaceURI();
}
private QName readCurrentElement() {
if (currentQName != null) {
return currentQName;
}
String ns = super.getNamespaceURI();
String name = super.getLocalName();
return new QName(ns, name);
}
}
private static class DelegatingNamespaceContext implements NamespaceContext {
private NamespaceContext nc;
private Map nsMap;
public DelegatingNamespaceContext(NamespaceContext nc, Map nsMap) {
this.nc = nc;
this.nsMap = nsMap;
}
public String getNamespaceURI(String prefix) {
return nc.getNamespaceURI(prefix);
}
public String getPrefix(String ns) {
String value = nsMap.get(ns);
if (value != null && value.length() == 0) {
return null;
}
return value != null ? nc.getPrefix(value) : nc.getPrefix(ns);
}
public Iterator getPrefixes(String ns) {
return nc.getPrefixes(ns);
}
}
}