You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2021/05/03 05:28:57 UTC
[tomee-jakarta] 05/06: cxf-rt-databinding-jaxb changes since 3.4.3
This is an automated email from the ASF dual-hosted git repository.
dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-jakarta.git
commit cafba39b3194571baba9e0c00632c73b1cff3ac8
Author: David Blevins <da...@gmail.com>
AuthorDate: Sun May 2 21:57:24 2021 -0700
cxf-rt-databinding-jaxb changes since 3.4.3
---
.../org/apache/cxf/jaxb/FactoryClassGenerator.java | 86 ++
.../java/org/apache/cxf/jaxb/JAXBDataBase.java | 192 ++++
.../java/org/apache/cxf/jaxb/JAXBDataBinding.java | 873 +++++++++++++++
.../org/apache/cxf/jaxb/JAXBEncoderDecoder.java | 1119 ++++++++++++++++++++
.../org/apache/cxf/jaxb/JAXBSchemaInitializer.java | 823 ++++++++++++++
.../org/apache/cxf/jaxb/io/DataReaderImpl.java | 207 ++++
.../org/apache/cxf/jaxb/io/DataWriterImpl.java | 321 ++++++
7 files changed, 3621 insertions(+)
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/FactoryClassGenerator.java b/transform/src/patch/java/org/apache/cxf/jaxb/FactoryClassGenerator.java
new file mode 100644
index 0000000..fe4c08b
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/FactoryClassGenerator.java
@@ -0,0 +1,86 @@
+/**
+ * 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.jaxb;
+
+import java.lang.reflect.Constructor;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.spi.ClassGeneratorClassLoader;
+import org.apache.cxf.common.util.ASMHelper;
+import org.apache.cxf.common.util.OpcodesProxy;
+import org.apache.cxf.common.util.ReflectionUtil;
+import org.apache.cxf.common.util.StringUtils;
+
+
+public class FactoryClassGenerator extends ClassGeneratorClassLoader implements FactoryClassCreator {
+ private final ASMHelper helper;
+ FactoryClassGenerator(Bus bus) {
+ super(bus);
+ helper = bus.getExtension(ASMHelper.class);
+ }
+ @SuppressWarnings("unused")
+ public Class<?> createFactory(Class<?> cls) {
+ String newClassName = cls.getName() + "Factory";
+ Class<?> factoryClass = findClass(newClassName, cls);
+ if (factoryClass != null) {
+ return factoryClass;
+ }
+ Constructor<?> contructor = ReflectionUtil.getDeclaredConstructors(cls)[0];
+ OpcodesProxy opcodes = helper.getOpCodes();
+ ASMHelper.ClassWriter cw = helper.createClassWriter();
+ ASMHelper.MethodVisitor mv;
+
+ cw.visit(opcodes.V1_6, opcodes.ACC_PUBLIC + opcodes.ACC_SUPER,
+ StringUtils.periodToSlashes(newClassName), null, "java/lang/Object", null);
+
+ cw.visitSource(cls.getSimpleName() + "Factory" + ".java", null);
+
+ mv = cw.visitMethod(opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(opcodes.ALOAD, 0);
+ mv.visitMethodInsn(opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ mv.visitInsn(opcodes.RETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ mv = cw.visitMethod(opcodes.ACC_PUBLIC, "create" + cls.getSimpleName(),
+ "()L" + StringUtils.periodToSlashes(cls.getName()) + ";", null, null);
+ mv.visitCode();
+ String name = cls.getName().replace('.', '/');
+ mv.visitTypeInsn(opcodes.NEW, name);
+ mv.visitInsn(opcodes.DUP);
+ StringBuilder paraString = new StringBuilder(32).append('(');
+
+ for (Class<?> paraClass : contructor.getParameterTypes()) {
+ mv.visitInsn(opcodes.ACONST_NULL);
+ paraString.append("Ljava/lang/Object;");
+ }
+ paraString.append(")V");
+
+ mv.visitMethodInsn(opcodes.INVOKESPECIAL, name, "<init>", paraString.toString(), false);
+
+ mv.visitInsn(opcodes.ARETURN);
+ mv.visitMaxs(0, 0);
+ mv.visitEnd();
+
+ cw.visitEnd();
+ return loadClass(newClassName, cls, cw.toByteArray());
+ }
+}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/JAXBDataBase.java b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBDataBase.java
new file mode 100644
index 0000000..55ac0cf
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBDataBase.java
@@ -0,0 +1,192 @@
+/**
+ * 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.jaxb;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.XmlAttachmentRef;
+import javax.xml.bind.annotation.XmlList;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.bind.attachment.AttachmentMarshaller;
+import javax.xml.bind.attachment.AttachmentUnmarshaller;
+import javax.xml.validation.Schema;
+
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.jaxb.attachment.JAXBAttachmentMarshaller;
+import org.apache.cxf.jaxb.attachment.JAXBAttachmentUnmarshaller;
+import org.apache.cxf.message.Attachment;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.service.model.AbstractMessageContainer;
+import org.apache.cxf.service.model.MessageInfo;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.cxf.service.model.OperationInfo;
+
+/**
+ *
+ */
+public abstract class JAXBDataBase {
+ static final Logger LOG = LogUtils.getL7dLogger(JAXBDataBase.class);
+
+ protected JAXBContext context;
+ protected Schema schema;
+ protected Collection<Attachment> attachments;
+ protected Integer mtomThreshold; // null if we should default.
+
+ protected JAXBDataBase(JAXBContext ctx) {
+ context = ctx;
+ }
+
+ public void setSchema(Schema s) {
+ this.schema = s;
+ }
+
+ public void setJAXBContext(JAXBContext jc) {
+ this.context = jc;
+ }
+
+ public Schema getSchema() {
+ return schema;
+ }
+ public JAXBContext getJAXBContext() {
+ return context;
+ }
+
+ public Collection<Attachment> getAttachments() {
+ return attachments;
+ }
+
+ public void setAttachments(Collection<Attachment> attachments) {
+ this.attachments = attachments;
+ }
+
+ protected AttachmentUnmarshaller getAttachmentUnmarshaller() {
+ return new JAXBAttachmentUnmarshaller(attachments);
+ }
+
+ protected AttachmentMarshaller getAttachmentMarshaller() {
+ return new JAXBAttachmentMarshaller(attachments, mtomThreshold);
+ }
+
+ public void setProperty(String prop, Object value) {
+ }
+
+ protected Annotation[] getJAXBAnnotation(MessagePartInfo mpi) {
+ List<Annotation> annoList = null;
+ if (mpi != null) {
+ annoList = extractJAXBAnnotations((Annotation[])mpi.getProperty("parameter.annotations"));
+ if (annoList == null) {
+ annoList = extractJAXBAnnotations(getReturnMethodAnnotations(mpi));
+ }
+ }
+ return annoList == null ? new Annotation[0] : annoList.toArray(new Annotation[0]);
+ }
+
+ private List<Annotation> extractJAXBAnnotations(Annotation[] anns) {
+ List<Annotation> annoList = null;
+ if (anns != null) {
+ for (Annotation ann : anns) {
+ if (ann instanceof XmlList || ann instanceof XmlAttachmentRef
+ || ann instanceof XmlJavaTypeAdapter) {
+ if (annoList == null) {
+ annoList = new ArrayList<>();
+ }
+ annoList.add(ann);
+ }
+ }
+ }
+ return annoList;
+ }
+
+ private Annotation[] getReturnMethodAnnotations(MessagePartInfo mpi) {
+ AbstractMessageContainer mi = mpi.getMessageInfo();
+ if (mi == null || !isOutputMessage(mi)) {
+ return null;
+ }
+ OperationInfo oi = mi.getOperation();
+ return oi != null ? (Annotation[])oi.getProperty("method.return.annotations") : null;
+ }
+
+ protected boolean isOutputMessage(AbstractMessageContainer messageContainer) {
+ if (messageContainer instanceof MessageInfo) {
+ return MessageInfo.Type.OUTPUT.equals(((MessageInfo)messageContainer).getType());
+ }
+ return false;
+ }
+
+ public Integer getMtomThreshold() {
+ return mtomThreshold;
+ }
+
+ public void setMtomThreshold(Integer threshold) {
+ this.mtomThreshold = threshold;
+ }
+
+ protected final boolean honorJAXBAnnotations(MessagePartInfo part) {
+ if (part == null) {
+ return false;
+ }
+ if (!part.isElement()) {
+ //RPC-Lit always needs to look for these
+ return true;
+ }
+ //certain cases that use XmlJavaTypeAdapters will require this and the
+ //JAXBSchemaInitializer will set this.
+ Boolean b = (Boolean)part.getProperty("honor.jaxb.annotations");
+ return b != null && b;
+ }
+
+ protected ValidationEventHandler getValidationEventHandler(String cn) {
+ try {
+ return (ValidationEventHandler)ClassLoaderUtils.loadClass(cn, getClass()).newInstance();
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
+ LOG.log(Level.INFO, "Could not create validation event handler", e);
+ }
+ return null;
+ }
+
+ protected ValidationEventHandler getValidationEventHandler(Message m, String property) {
+ Object value = m.getContextualProperty(property);
+ ValidationEventHandler veventHandler;
+ if (value instanceof String) {
+ veventHandler = getValidationEventHandler((String)value);
+ } else {
+ veventHandler = (ValidationEventHandler)value;
+ }
+ if (veventHandler == null) {
+ value = m.getContextualProperty(JAXBDataBinding.VALIDATION_EVENT_HANDLER);
+ if (value instanceof String) {
+ veventHandler = getValidationEventHandler((String)value);
+ } else {
+ veventHandler = (ValidationEventHandler)value;
+ }
+ }
+ return veventHandler;
+ }
+
+
+}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/JAXBDataBinding.java b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBDataBinding.java
new file mode 100644
index 0000000..a66e9bf
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBDataBinding.java
@@ -0,0 +1,873 @@
+/**
+ * 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.jaxb;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+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.ValidationEventHandler;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import org.xml.sax.InputSource;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.injection.NoJSR250Annotations;
+import org.apache.cxf.common.jaxb.JAXBBeanInfo;
+import org.apache.cxf.common.jaxb.JAXBContextCache;
+import org.apache.cxf.common.jaxb.JAXBContextCache.CachedContextAndSchemas;
+import org.apache.cxf.common.jaxb.JAXBContextProxy;
+import org.apache.cxf.common.jaxb.JAXBUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.PackageUtils;
+import org.apache.cxf.common.util.PropertyUtils;
+import org.apache.cxf.common.util.ReflectionUtil;
+import org.apache.cxf.common.xmlschema.SchemaCollection;
+import org.apache.cxf.databinding.AbstractInterceptorProvidingDataBinding;
+import org.apache.cxf.databinding.AbstractWrapperHelper;
+import org.apache.cxf.databinding.DataReader;
+import org.apache.cxf.databinding.DataWriter;
+import org.apache.cxf.databinding.WrapperCapableDatabinding;
+import org.apache.cxf.databinding.WrapperHelper;
+import org.apache.cxf.interceptor.InterceptorProvider;
+import org.apache.cxf.jaxb.attachment.JAXBAttachmentSchemaValidationHack;
+import org.apache.cxf.jaxb.io.DataReaderImpl;
+import org.apache.cxf.jaxb.io.DataWriterImpl;
+import org.apache.cxf.resource.URIResolver;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.factory.ServiceConstructionException;
+import org.apache.cxf.service.model.MessageInfo;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.cxf.staxutils.StaxUtils;
+import org.apache.cxf.ws.addressing.ObjectFactory;
+
+@NoJSR250Annotations
+public class JAXBDataBinding extends AbstractInterceptorProvidingDataBinding
+ implements WrapperCapableDatabinding, InterceptorProvider {
+
+ public static final String READER_VALIDATION_EVENT_HANDLER = "jaxb-reader-validation-event-handler";
+ public static final String VALIDATION_EVENT_HANDLER = "jaxb-validation-event-handler";
+ public static final String SET_VALIDATION_EVENT_HANDLER = "set-jaxb-validation-event-handler";
+ public static final String WRITER_VALIDATION_EVENT_HANDLER = "jaxb-writer-validation-event-handler";
+
+ public static final String SCHEMA_RESOURCE = "SCHEMRESOURCE";
+ public static final String MTOM_THRESHOLD = "org.apache.cxf.jaxb.mtomThreshold";
+
+ public static final String UNWRAP_JAXB_ELEMENT = "unwrap.jaxb.element";
+
+ public static final String USE_JAXB_BRIDGE = "use.jaxb.bridge";
+
+ public static final String JAXB_SCAN_PACKAGES = "jaxb.scanPackages";
+
+ private static final Logger LOG = LogUtils.getLogger(JAXBDataBinding.class);
+
+ private static final Class<?>[] SUPPORTED_READER_FORMATS = new Class<?>[] {Node.class,
+ XMLEventReader.class,
+ XMLStreamReader.class};
+ private static final Class<?>[] SUPPORTED_WRITER_FORMATS = new Class<?>[] {OutputStream.class,
+ Node.class,
+ XMLEventWriter.class,
+ XMLStreamWriter.class};
+
+ private static class DelayedDOMResult extends DOMResult {
+ private final URL resource;
+ private final String publicId;
+ DelayedDOMResult(URL url, String sysId, String pId) {
+ super(null, sysId);
+ resource = url;
+ publicId = pId;
+ }
+ public synchronized Node getNode() {
+ Node nd = super.getNode();
+ if (nd == null) {
+ try {
+ InputSource src = new InputSource(resource.openStream());
+ src.setSystemId(this.getSystemId());
+ src.setPublicId(publicId);
+ Document doc = StaxUtils.read(src);
+ setNode(doc);
+ nd = super.getNode();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ return nd;
+ }
+ }
+ private static final Map<String, DOMResult> BUILT_IN_SCHEMAS = new HashMap<>();
+ static {
+ try (URIResolver resolver = new URIResolver()) {
+ try {
+ resolver.resolve("", "classpath:/schemas/wsdl/ws-addr-wsdl.xsd", JAXBDataBinding.class);
+ if (resolver.isResolved()) {
+ resolver.getInputStream().close();
+ DOMResult dr = new DelayedDOMResult(resolver.getURL(),
+ "classpath:/schemas/wsdl/ws-addr-wsdl.xsd",
+ "http://www.w3.org/2005/02/addressing/wsdl");
+ BUILT_IN_SCHEMAS.put("http://www.w3.org/2005/02/addressing/wsdl", dr);
+ resolver.unresolve();
+ }
+ } catch (Exception e) {
+ //IGNORE
+ }
+ try {
+ resolver.resolve("", "classpath:/schemas/wsdl/ws-addr.xsd", JAXBDataBinding.class);
+ if (resolver.isResolved()) {
+ resolver.getInputStream().close();
+ DOMResult dr = new DelayedDOMResult(resolver.getURL(),
+ "classpath:/schemas/wsdl/ws-addr.xsd",
+ "http://www.w3.org/2005/08/addressing");
+ BUILT_IN_SCHEMAS.put("http://www.w3.org/2005/08/addressing", dr);
+ resolver.unresolve();
+ }
+ } catch (Exception e) {
+ //IGNORE
+ }
+ try {
+ resolver.resolve("", "classpath:/schemas/wsdl/wsrm.xsd", JAXBDataBinding.class);
+ if (resolver.isResolved()) {
+ resolver.getInputStream().close();
+ DOMResult dr = new DelayedDOMResult(resolver.getURL(),
+ "classpath:/schemas/wsdl/wsrm.xsd",
+ "http://schemas.xmlsoap.org/ws/2005/02/rm");
+ BUILT_IN_SCHEMAS.put("http://schemas.xmlsoap.org/ws/2005/02/rm", dr);
+ resolver.unresolve();
+ }
+ } catch (Exception e) {
+ //IGNORE
+ }
+ } catch (Exception e) {
+ //IGNORE
+ }
+ }
+
+ Class<?>[] extraClass;
+
+ JAXBContext context;
+ Set<Class<?>> contextClasses;
+ Collection<Object> typeRefs = new ArrayList<>();
+
+ Class<?> cls;
+
+ private Map<String, Object> contextProperties = new HashMap<>();
+ private List<XmlAdapter<?, ?>> adapters = new ArrayList<>();
+ private Map<String, Object> marshallerProperties = new HashMap<>();
+ private Map<String, Object> unmarshallerProperties = new HashMap<>();
+ private Unmarshaller.Listener unmarshallerListener;
+ private Marshaller.Listener marshallerListener;
+ private ValidationEventHandler validationEventHandler;
+ private Object escapeHandler;
+ private Object noEscapeHandler;
+
+ private boolean unwrapJAXBElement = true;
+ private boolean scanPackages = true;
+ private boolean qualifiedSchemas;
+
+ public JAXBDataBinding() {
+ }
+
+ public JAXBDataBinding(boolean q) {
+ this.qualifiedSchemas = q;
+ }
+
+ public JAXBDataBinding(Class<?>... classes) throws JAXBException {
+ contextClasses = new LinkedHashSet<>(Arrays.asList(classes));
+ setContext(createJAXBContext(contextClasses)); //NOPMD - specifically allow this
+ }
+ public JAXBDataBinding(boolean qualified, Map<String, Object> props) throws JAXBException {
+ this(qualified);
+ if (props != null && props.get("jaxb.additionalContextClasses") != null) {
+ Object o = props.get("jaxb.additionalContextClasses");
+ if (o instanceof Class) {
+ o = new Class[] {(Class<?>)o};
+ }
+ extraClass = (Class[])o;
+ }
+
+ // the default for scan packages is true, so the jaxb scan packages
+ // property must be explicitly set to false to disable it
+ if (PropertyUtils.isFalse(props, JAXB_SCAN_PACKAGES)) {
+ scanPackages = false;
+ }
+ }
+
+ public JAXBDataBinding(JAXBContext context) {
+ this();
+ setContext(context);
+ }
+
+ protected boolean getQualifiedSchemas() {
+ return qualifiedSchemas;
+ }
+
+ public JAXBContext getContext() {
+ return context;
+ }
+
+ public final void setContext(JAXBContext ctx) {
+ context = ctx;
+ //create default MininumEscapeHandler
+ escapeHandler = JAXBUtils.createMininumEscapeHandler(ctx.getClass());
+ noEscapeHandler = JAXBUtils.createNoEscapeHandler(ctx.getClass());
+ }
+
+ public Object getEscapeHandler() {
+ return escapeHandler;
+ }
+
+ public void setEscapeHandler(Object handler) {
+ escapeHandler = handler;
+ }
+
+ public void applyEscapeHandler(boolean escape, Consumer<Object> consumer) {
+ if (escape) {
+ consumer.accept(escapeHandler);
+ } else if (noEscapeHandler != null) {
+ consumer.accept(noEscapeHandler);
+ }
+ }
+
+
+ @SuppressWarnings("unchecked")
+ public <T> DataWriter<T> createWriter(Class<T> c) {
+
+ Integer mtomThresholdInt = Integer.valueOf(getMtomThreshold());
+ if (c == XMLStreamWriter.class) {
+ DataWriterImpl<XMLStreamWriter> r
+ = new DataWriterImpl<>(getBus(), this, true);
+ r.setMtomThreshold(mtomThresholdInt);
+ return (DataWriter<T>)r;
+ } else if (c == OutputStream.class) {
+ DataWriterImpl<OutputStream> r = new DataWriterImpl<>(getBus(), this, false);
+ r.setMtomThreshold(mtomThresholdInt);
+ return (DataWriter<T>)r;
+ } else if (c == XMLEventWriter.class) {
+ DataWriterImpl<XMLEventWriter> r = new DataWriterImpl<>(getBus(), this, true);
+ r.setMtomThreshold(mtomThresholdInt);
+ return (DataWriter<T>)r;
+ } else if (c == Node.class) {
+ DataWriterImpl<Node> r = new DataWriterImpl<>(getBus(), this, false);
+ r.setMtomThreshold(mtomThresholdInt);
+ return (DataWriter<T>)r;
+ }
+ return null;
+ }
+
+ public Class<?>[] getSupportedWriterFormats() {
+ return SUPPORTED_WRITER_FORMATS;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> DataReader<T> createReader(Class<T> c) {
+ DataReader<T> dr = null;
+ if (c == XMLStreamReader.class) {
+ dr = (DataReader<T>)new DataReaderImpl<XMLStreamReader>(this, unwrapJAXBElement);
+ } else if (c == XMLEventReader.class) {
+ dr = (DataReader<T>)new DataReaderImpl<XMLEventReader>(this, unwrapJAXBElement);
+ } else if (c == Node.class) {
+ dr = (DataReader<T>)new DataReaderImpl<Node>(this, unwrapJAXBElement);
+ }
+
+ return dr;
+ }
+
+ public Class<?>[] getSupportedReaderFormats() {
+ return SUPPORTED_READER_FORMATS;
+ }
+
+ @SuppressWarnings("unchecked")
+ public synchronized void initialize(Service service) {
+
+ inInterceptors.addIfAbsent(JAXBAttachmentSchemaValidationHack.INSTANCE);
+ inFaultInterceptors.addIfAbsent(JAXBAttachmentSchemaValidationHack.INSTANCE);
+
+ // context is already set, don't redo it
+ if (context != null) {
+ return;
+ }
+
+ contextClasses = new LinkedHashSet<>();
+
+ for (ServiceInfo serviceInfo : service.getServiceInfos()) {
+ JAXBContextInitializer initializer = new JAXBContextInitializer(getBus(), serviceInfo, contextClasses,
+ typeRefs, this.getUnmarshallerProperties());
+ initializer.walk();
+ if (serviceInfo.getProperty("extra.class") != null) {
+ Set<Class<?>> exClasses = serviceInfo.getProperty("extra.class", Set.class);
+ contextClasses.addAll(exClasses);
+ }
+
+ }
+
+ String tns = getNamespaceToUse(service);
+ final CachedContextAndSchemas cachedContextAndSchemas;
+ try {
+ cachedContextAndSchemas = createJAXBContextAndSchemas(contextClasses, tns);
+ } catch (JAXBException e1) {
+ throw new ServiceConstructionException(e1);
+ }
+ final JAXBContext ctx = cachedContextAndSchemas.getContext();
+ if (LOG.isLoggable(Level.FINE)) {
+ LOG.log(Level.FINE, "CREATED_JAXB_CONTEXT", new Object[] {ctx, contextClasses});
+ }
+ setContext(ctx);
+
+ for (ServiceInfo serviceInfo : service.getServiceInfos()) {
+ SchemaCollection col = serviceInfo.getXmlSchemaCollection();
+
+ if (col.getXmlSchemas().length > 1) {
+ // someone has already filled in the types
+ justCheckForJAXBAnnotations(serviceInfo);
+ continue;
+ }
+
+ boolean schemasFromCache = false;
+ Collection<DOMSource> schemas = getSchemas();
+ if (schemas == null || schemas.isEmpty()) {
+ schemas = cachedContextAndSchemas.getSchemas();
+ if (schemas != null) {
+ schemasFromCache = true;
+ }
+ } else {
+ schemasFromCache = true;
+ }
+ Set<DOMSource> bi = new LinkedHashSet<>();
+ if (schemas == null) {
+ schemas = new LinkedHashSet<>();
+ try {
+ for (DOMResult r : generateJaxbSchemas()) {
+ DOMSource src = new DOMSource(r.getNode(), r.getSystemId());
+ if (isInBuiltInSchemas(r)) {
+ bi.add(src);
+ } else {
+ schemas.add(src);
+ }
+ }
+ //put any builtins at the end. Anything that DOES import them
+ //will cause it to load automatically and we'll skip them later
+ schemas.addAll(bi);
+ } catch (IOException e) {
+ throw new ServiceConstructionException("SCHEMA_GEN_EXC", LOG, e);
+ }
+ }
+ for (DOMSource r : schemas) {
+ if (bi.contains(r)) {
+ String ns = ((Document)r.getNode()).getDocumentElement().getAttribute("targetNamespace");
+ if (serviceInfo.getSchema(ns) != null) {
+ continue;
+ }
+ }
+ //StaxUtils.print(r.getNode());
+ //System.out.println();
+ addSchemaDocument(serviceInfo,
+ col,
+ (Document)r.getNode(),
+ r.getSystemId());
+ }
+
+ JAXBSchemaInitializer schemaInit = new JAXBSchemaInitializer(serviceInfo, col, context,
+ this.qualifiedSchemas, tns);
+ schemaInit.walk();
+ if (cachedContextAndSchemas != null && !schemasFromCache) {
+ cachedContextAndSchemas.setSchemas(schemas);
+ }
+ }
+ }
+
+ protected void justCheckForJAXBAnnotations(ServiceInfo serviceInfo) {
+ for (MessageInfo mi: serviceInfo.getMessages().values()) {
+ for (MessagePartInfo mpi : mi.getMessageParts()) {
+ checkForJAXBAnnotations(mpi, serviceInfo.getXmlSchemaCollection(), serviceInfo.getTargetNamespace());
+ }
+ }
+ }
+ private void checkForJAXBAnnotations(MessagePartInfo mpi, SchemaCollection schemaCollection, String ns) {
+ Annotation[] anns = (Annotation[])mpi.getProperty("parameter.annotations");
+ JAXBContextProxy ctx = JAXBUtils.createJAXBContextProxy(context, schemaCollection, ns);
+ XmlJavaTypeAdapter jta = JAXBSchemaInitializer.findFromTypeAdapter(ctx, mpi.getTypeClass(), anns);
+ if (jta != null) {
+ JAXBBeanInfo jtaBeanInfo = JAXBSchemaInitializer.findFromTypeAdapter(ctx, jta.value());
+ JAXBBeanInfo beanInfo = JAXBSchemaInitializer.getBeanInfo(ctx, mpi.getTypeClass());
+ if (jtaBeanInfo != beanInfo) {
+ mpi.setProperty("parameter.annotations", anns);
+ mpi.setProperty("honor.jaxb.annotations", Boolean.TRUE);
+ }
+ }
+ }
+
+ protected String getNamespaceToUse(Service service) {
+ if ("true".equals(service.get("org.apache.cxf.databinding.namespace"))) {
+ return null;
+ }
+ final String tns;
+ if (!service.getServiceInfos().isEmpty()) {
+ tns = service.getServiceInfos().get(0).getInterface().getName().getNamespaceURI();
+ } else {
+ tns = service.getName().getNamespaceURI();
+ }
+ return tns;
+ }
+
+ public void setExtraClass(Class<?>[] userExtraClass) {
+ extraClass = userExtraClass;
+ }
+
+ public Class<?>[] getExtraClass() {
+ return extraClass;
+ }
+
+ // default access for tests.
+ List<DOMResult> generateJaxbSchemas() throws IOException {
+ return JAXBUtils.generateJaxbSchemas(context, BUILT_IN_SCHEMAS);
+ }
+
+ public JAXBContext createJAXBContext(Set<Class<?>> classes) throws JAXBException {
+ return createJAXBContext(classes, null);
+ }
+
+ public JAXBContext createJAXBContext(Set<Class<?>> classes, String defaultNs) throws JAXBException {
+ return createJAXBContextAndSchemas(classes, defaultNs).getContext();
+ }
+
+ public CachedContextAndSchemas createJAXBContextAndSchemas(Set<Class<?>> classes,
+ String defaultNs)
+ throws JAXBException {
+ //add user extra class into jaxb context
+ if (extraClass != null && extraClass.length > 0) {
+ for (Class<?> clz : extraClass) {
+ classes.add(clz);
+ }
+ }
+ if (scanPackages) {
+ JAXBContextCache.scanPackages(classes);
+ }
+ addWsAddressingTypes(classes);
+
+ return JAXBContextCache.getCachedContextAndSchemas(classes, defaultNs,
+ contextProperties,
+ typeRefs, true);
+ }
+
+
+ private void addWsAddressingTypes(Set<Class<?>> classes) {
+ if (classes.contains(ObjectFactory.class)) {
+ // ws-addressing is used, lets add the specific types
+ try {
+ classes.add(Class.forName("org.apache.cxf.ws.addressing.wsdl.ObjectFactory"));
+ classes.add(Class.forName("org.apache.cxf.ws.addressing.wsdl.AttributedQNameType"));
+ classes.add(Class.forName("org.apache.cxf.ws.addressing.wsdl.ServiceNameType"));
+ } catch (ClassNotFoundException unused) {
+ // REVISIT - ignorable if WS-ADDRESSING not available?
+ // maybe add a way to allow interceptors to add stuff to the
+ // context?
+ }
+ }
+ }
+
+ public Set<Class<?>> getContextClasses() {
+ return Collections.unmodifiableSet(this.contextClasses);
+ }
+
+ /**
+ * Return a map of properties. These properties are passed to
+ * JAXBContext.newInstance when this object creates a context.
+ *
+ * @return the map of JAXB context properties.
+ */
+ public Map<String, Object> getContextProperties() {
+ return contextProperties;
+ }
+
+ /**
+ * Set a map of JAXB context properties. These properties are passed to
+ * JAXBContext.newInstance when this object creates a context. Note that if
+ * you create a JAXB context elsewhere, you will not respect these
+ * properties unless you handle it manually.
+ *
+ * @param contextProperties map of properties.
+ */
+ public void setContextProperties(Map<String, Object> contextProperties) {
+ this.contextProperties = contextProperties;
+ }
+
+ public List<XmlAdapter<?, ?>> getConfiguredXmlAdapters() {
+ return adapters;
+ }
+
+ public void setConfiguredXmlAdapters(List<XmlAdapter<?, ?>> adpters) {
+ this.adapters = adpters;
+ }
+
+ /**
+ * Return a map of properties. These properties are set into the JAXB
+ * Marshaller (via Marshaller.setProperty(...) when the marshaller is
+ * created.
+ *
+ * @return the map of JAXB marshaller properties.
+ */
+ public Map<String, Object> getMarshallerProperties() {
+ return marshallerProperties;
+ }
+
+ /**
+ * Set a map of JAXB marshaller properties. These properties are set into
+ * the JAXB Marshaller (via Marshaller.setProperty(...) when the marshaller
+ * is created.
+ *
+ * @param marshallerProperties map of properties.
+ */
+ public void setMarshallerProperties(Map<String, Object> marshallerProperties) {
+ this.marshallerProperties = marshallerProperties;
+ }
+
+
+ /**
+ * Return a map of properties. These properties are set into the JAXB
+ * Unmarshaller (via Unmarshaller.setProperty(...) when the unmarshaller is
+ * created.
+ *
+ * @return the map of JAXB unmarshaller properties.
+ */
+ public Map<String, Object> getUnmarshallerProperties() {
+ return unmarshallerProperties;
+ }
+
+ /**
+ * Set a map of JAXB unmarshaller properties. These properties are set into
+ * the JAXB Unmarshaller (via Unmarshaller.setProperty(...) when the unmarshaller
+ * is created.
+ *
+ * @param unmarshallerProperties map of properties.
+ */
+ public void setUnmarshallerProperties(Map<String, Object> unmarshallerProperties) {
+ this.unmarshallerProperties = unmarshallerProperties;
+ }
+
+ /**
+ * Returns the Unmarshaller.Listener that will be registered on the Unmarshallers
+ * @return
+ */
+ public Unmarshaller.Listener getUnmarshallerListener() {
+ return unmarshallerListener;
+ }
+
+ /**
+ * Sets the Unmarshaller.Listener that will be registered on the Unmarshallers
+ * @param unmarshallerListener
+ */
+ public void setUnmarshallerListener(Unmarshaller.Listener unmarshallerListener) {
+ this.unmarshallerListener = unmarshallerListener;
+ }
+ /**
+ * Returns the Marshaller.Listener that will be registered on the Marshallers
+ * @return
+ */
+ public Marshaller.Listener getMarshallerListener() {
+ return marshallerListener;
+ }
+
+ /**
+ * Sets the Marshaller.Listener that will be registered on the Marshallers
+ * @param marshallerListener
+ */
+ public void setMarshallerListener(Marshaller.Listener marshallerListener) {
+ this.marshallerListener = marshallerListener;
+ }
+
+
+ public ValidationEventHandler getValidationEventHandler() {
+ return validationEventHandler;
+ }
+
+ public void setValidationEventHandler(ValidationEventHandler validationEventHandler) {
+ this.validationEventHandler = validationEventHandler;
+ }
+
+
+ public boolean isUnwrapJAXBElement() {
+ return unwrapJAXBElement;
+ }
+
+ public void setUnwrapJAXBElement(boolean unwrapJAXBElement) {
+ this.unwrapJAXBElement = unwrapJAXBElement;
+ }
+
+ public WrapperHelper createWrapperHelper(Class<?> wrapperType, QName wrapperName, List<String> partNames,
+ List<String> elTypeNames, List<Class<?>> partClasses) {
+ List<Method> getMethods = new ArrayList<>(partNames.size());
+ List<Method> setMethods = new ArrayList<>(partNames.size());
+ List<Method> jaxbMethods = new ArrayList<>(partNames.size());
+ List<Field> fields = new ArrayList<>(partNames.size());
+
+ Method[] allMethods = wrapperType.getMethods();
+ String packageName = PackageUtils.getPackageName(wrapperType);
+
+ //if wrappertype class is generated by ASM, getPackage() always return null
+ if (wrapperType.getPackage() != null) {
+ packageName = wrapperType.getPackage().getName();
+ }
+
+ String objectFactoryClassName = packageName + ".ObjectFactory";
+
+ Object objectFactory = null;
+ try {
+ objectFactory = wrapperType.getClassLoader().loadClass(objectFactoryClassName).newInstance();
+ } catch (Exception e) {
+ //ignore, probably won't need it
+ }
+ Method[] allOFMethods;
+ if (objectFactory != null) {
+ allOFMethods = objectFactory.getClass().getMethods();
+ } else {
+ allOFMethods = new Method[0];
+ }
+
+ for (int x = 0; x < partNames.size(); x++) {
+ String partName = partNames.get(x);
+ if (partName == null) {
+ getMethods.add(null);
+ setMethods.add(null);
+ fields.add(null);
+ jaxbMethods.add(null);
+ continue;
+ }
+
+ String elementType = elTypeNames.get(x);
+
+ String getAccessor = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.GETTER);
+ String setAccessor = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.SETTER);
+ Method getMethod = null;
+ Method setMethod = null;
+ Class<?> valueClass = wrapperType;
+
+ try {
+ getMethod = valueClass.getMethod(getAccessor, AbstractWrapperHelper.NO_CLASSES);
+ } catch (NoSuchMethodException ex) {
+ //ignore for now
+ }
+
+ Field elField = getElField(partName, valueClass);
+ if (getMethod == null
+ && elementType != null
+ && "boolean".equalsIgnoreCase(elementType)
+ && (elField == null
+ || (!Collection.class.isAssignableFrom(elField.getType())
+ && !elField.getType().isArray()))) {
+
+ try {
+ String newAcc = getAccessor.replaceFirst("get", "is");
+ getMethod = wrapperType.getMethod(newAcc, AbstractWrapperHelper.NO_CLASSES);
+ } catch (NoSuchMethodException ex) {
+ //ignore for now
+ }
+ }
+ if (getMethod == null
+ && "return".equals(partName)) {
+ //RI generated code uses this
+ try {
+ getMethod = valueClass.getMethod("get_return", AbstractWrapperHelper.NO_CLASSES);
+ } catch (NoSuchMethodException ex) {
+ try {
+ getMethod = valueClass.getMethod("is_return",
+ new Class[0]);
+ } catch (NoSuchMethodException ex2) {
+ //ignore for now
+ }
+ }
+ }
+ if (getMethod == null && elField != null) {
+ getAccessor = JAXBUtils.nameToIdentifier(elField.getName(), JAXBUtils.IdentifierType.GETTER);
+ setAccessor = JAXBUtils.nameToIdentifier(elField.getName(), JAXBUtils.IdentifierType.SETTER);
+ try {
+ getMethod = valueClass.getMethod(getAccessor, AbstractWrapperHelper.NO_CLASSES);
+ } catch (NoSuchMethodException ex) {
+ //ignore for now
+ }
+ }
+ String setAccessor2 = setAccessor;
+ if ("return".equals(partName)) {
+ //some versions of jaxb map "return" to "set_return" instead of "setReturn"
+ setAccessor2 = "set_return";
+ }
+
+ for (Method method : allMethods) {
+ if (method.getParameterTypes() != null && method.getParameterTypes().length == 1
+ && (setAccessor.equals(method.getName())
+ || setAccessor2.equals(method.getName()))) {
+ setMethod = method;
+ break;
+ }
+ }
+
+ getMethods.add(getMethod);
+ setMethods.add(setMethod);
+ if (setMethod != null
+ && JAXBElement.class.isAssignableFrom(setMethod.getParameterTypes()[0])) {
+
+ Type t = setMethod.getGenericParameterTypes()[0];
+ Class<?> pcls = null;
+ if (t instanceof ParameterizedType) {
+ t = ((ParameterizedType)t).getActualTypeArguments()[0];
+ }
+ if (t instanceof Class) {
+ pcls = (Class<?>)t;
+ }
+
+ String methodName = "create" + wrapperType.getSimpleName()
+ + setMethod.getName().substring(3);
+
+ for (Method m : allOFMethods) {
+ if (m.getName().equals(methodName)
+ && m.getParameterTypes().length == 1
+ && (pcls == null
+ || pcls.equals(m.getParameterTypes()[0]))) {
+ jaxbMethods.add(m);
+ }
+ }
+ } else {
+ jaxbMethods.add(null);
+ }
+
+ if (elField != null) {
+ // JAXB Type get XmlElement Annotation
+ XmlElement el = elField.getAnnotation(XmlElement.class);
+ if (el != null
+ && (partName.equals(el.name())
+ || "##default".equals(el.name()))) {
+ ReflectionUtil.setAccessible(elField);
+ fields.add(elField);
+ } else {
+ if (getMethod == null && setMethod == null) {
+ if (el != null) {
+ LOG.warning("Could not create accessor for property " + partName
+ + " of type " + wrapperType.getName() + " as the @XmlElement "
+ + "defines the name as " + el.name());
+ } else {
+ LOG.warning("Could not create accessor for property " + partName
+ + " of type " + wrapperType.getName());
+ }
+ }
+ fields.add(null);
+ }
+ } else {
+ fields.add(null);
+ }
+
+ }
+
+ return createWrapperHelper(getBus(), wrapperType,
+ setMethods.toArray(new Method[0]),
+ getMethods.toArray(new Method[0]),
+ jaxbMethods.toArray(new Method[0]),
+ fields.toArray(new Field[0]),
+ objectFactory);
+ }
+
+ public static boolean isInBuiltInSchemas(DOMResult schema) {
+ return BUILT_IN_SCHEMAS.containsValue(schema);
+ }
+
+ private static Field getElField(String partName, final Class<?> wrapperType) {
+ String fieldName = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.VARIABLE);
+ Field[] fields = ReflectionUtil.getDeclaredFields(wrapperType);
+ for (Field field : fields) {
+ XmlElement el = field.getAnnotation(XmlElement.class);
+ if (el != null
+ && partName.equals(el.name())) {
+ return field;
+ }
+
+ XmlElementRef xmlElementRefAnnotation = field.getAnnotation(XmlElementRef.class);
+ if (xmlElementRefAnnotation != null && partName.equals(xmlElementRefAnnotation.name())) {
+ return field;
+ }
+
+ if (field.getName().equals(fieldName)) {
+ return field;
+ }
+ }
+ return null;
+ }
+
+
+ private static WrapperHelper createWrapperHelper(Bus bus, Class<?> wrapperType, Method[] setMethods,
+ Method[] getMethods, Method[] jaxbMethods,
+ Field[] fields, Object objectFactory) {
+
+ WrapperHelper wh = compileWrapperHelper(bus, wrapperType, setMethods, getMethods, jaxbMethods, fields,
+ objectFactory);
+
+ if (wh == null) {
+ wh = new JAXBWrapperHelper(wrapperType, setMethods, getMethods, jaxbMethods, fields,
+ objectFactory);
+ }
+ return wh;
+ }
+
+ private static WrapperHelper compileWrapperHelper(Bus bus, Class<?> wrapperType, Method[] setMethods,
+ Method[] getMethods, Method[] jaxbMethods,
+ Field[] fields, Object objectFactory) {
+ try {
+ WrapperHelperCreator creator = bus.getExtension(WrapperHelperCreator.class);
+ return creator.compile(wrapperType, setMethods, getMethods,
+ jaxbMethods, fields, objectFactory);
+ } catch (Throwable t) {
+ // Some error - probably a bad version of ASM or similar
+ return null;
+ }
+ }
+
+}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
new file mode 100644
index 0000000..4d177e9
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBEncoderDecoder.java
@@ -0,0 +1,1119 @@
+/**
+ * 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.jaxb;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.logging.Logger;
+
+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.XmlAccessOrder;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorOrder;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
+import javax.xml.bind.attachment.AttachmentMarshaller;
+import javax.xml.bind.attachment.AttachmentUnmarshaller;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.stream.util.StreamReaderDelegate;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.jaxb.JAXBUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.ReflectionUtil;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.helpers.CastUtils;
+import org.apache.cxf.helpers.DOMUtils;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.cxf.service.model.SchemaInfo;
+import org.apache.cxf.staxutils.DepthXMLStreamReader;
+import org.apache.cxf.staxutils.StaxUtils;
+import org.apache.cxf.staxutils.W3CDOMStreamWriter;
+import org.apache.cxf.staxutils.W3CNamespaceContext;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaSimpleType;
+import org.apache.ws.commons.schema.XmlSchemaSimpleTypeList;
+import org.apache.ws.commons.schema.constants.Constants;
+
+/**
+ * Utility functions for JAXB.
+ */
+public final class JAXBEncoderDecoder {
+ private static final class AddXSITypeStreamReader extends StreamReaderDelegate {
+ private boolean first = true;
+ private int offset = 1;
+ private final QName typeQName;
+
+ private AddXSITypeStreamReader(XMLStreamReader reader, QName typeQName) {
+ super(reader);
+ this.typeQName = typeQName;
+ }
+
+ public int getAttributeCount() {
+ return super.getAttributeCount() + offset;
+ }
+
+ public String getAttributeLocalName(int index) {
+ if (first && index == 0) {
+ return "type";
+ }
+ return super.getAttributeLocalName(index - offset);
+ }
+
+ public QName getAttributeName(int index) {
+ if (first && index == 0) {
+ return new QName(Constants.URI_2001_SCHEMA_XSI, "type");
+ }
+ return super.getAttributeName(index - offset);
+ }
+
+ public String getAttributeNamespace(int index) {
+ if (first && index == 0) {
+ return Constants.URI_2001_SCHEMA_XSI;
+ }
+ return super.getAttributeNamespace(index - offset);
+ }
+
+ public String getAttributePrefix(int index) {
+ if (first && index == 0) {
+ return "xsi";
+ }
+ return super.getAttributePrefix(index - offset);
+ }
+
+ public String getAttributeType(int index) {
+ if (first && index == 0) {
+ return "#TEXT";
+ }
+ return super.getAttributeType(index - offset);
+ }
+
+ public String getAttributeValue(int index) {
+ if (first && index == 0) {
+ String pfx = this.getNamespaceContext().getPrefix(typeQName.getNamespaceURI());
+ if (StringUtils.isEmpty(pfx)) {
+ return typeQName.getLocalPart();
+ }
+ return pfx + ":" + typeQName.getLocalPart();
+ }
+ return super.getAttributeValue(index - offset);
+ }
+
+ public int next() throws XMLStreamException {
+ first = false;
+ offset = 0;
+ return super.next();
+ }
+
+ public String getAttributeValue(String namespaceUri,
+ String localName) {
+ if (first
+ && Constants.URI_2001_SCHEMA_XSI.equals(namespaceUri)
+ && "type".equals(localName)) {
+ String pfx = this.getNamespaceContext().getPrefix(typeQName.getNamespaceURI());
+ if (StringUtils.isEmpty(pfx)) {
+ return typeQName.getLocalPart();
+ }
+ return pfx + ":" + typeQName.getLocalPart();
+ }
+ return super.getAttributeValue(namespaceUri, localName);
+ }
+ }
+
+ private static final Logger LOG = LogUtils.getLogger(JAXBEncoderDecoder.class);
+
+ private JAXBEncoderDecoder() {
+ }
+
+ public static void marshall(Marshaller marshaller,
+ Object elValue,
+ MessagePartInfo part,
+ Object source) {
+ try {
+ // The Marshaller.JAXB_FRAGMENT will tell the Marshaller not to
+ // generate the xml declaration.
+ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, false);
+ } catch (javax.xml.bind.PropertyException e) {
+ // intentionally empty.
+ }
+
+ Class<?> cls = null;
+ if (part != null) {
+ cls = part.getTypeClass();
+ }
+
+ if (cls == null) {
+ cls = null != elValue ? elValue.getClass() : null;
+ }
+
+ if (cls != null && cls.isArray() && elValue instanceof Collection) {
+ Collection<?> col = (Collection<?>)elValue;
+ elValue = col.toArray((Object[])Array.newInstance(cls.getComponentType(), col.size()));
+ }
+
+ try {
+ Object mObj = elValue;
+ QName elName = null;
+ if (part != null) {
+ elName = part.getConcreteName();
+ }
+
+ if (null != elName) {
+
+ if (part != null && part.getXmlSchema() instanceof XmlSchemaElement) {
+
+ XmlSchemaElement el = (XmlSchemaElement)part.getXmlSchema();
+
+ if (mObj.getClass().isArray()
+ && el.getSchemaType() instanceof XmlSchemaSimpleType
+ && ((XmlSchemaSimpleType)el.getSchemaType()).
+ getContent() instanceof XmlSchemaSimpleTypeList) {
+ mObj = Arrays.asList((Object[])mObj);
+ writeObject(marshaller, source, newJAXBElement(elName, cls, mObj));
+ } else if (part.getMessageInfo().getOperation().isUnwrapped()
+ && (mObj.getClass().isArray() || mObj instanceof List)
+ && el.getMaxOccurs() != 1) {
+ writeArrayObject(marshaller,
+ source,
+ elName,
+ mObj);
+ } else {
+ writeObject(marshaller, source, newJAXBElement(elName, cls, mObj));
+ }
+ } else if (byte[].class == cls && part.getTypeQName() != null
+ && "hexBinary".equals(part.getTypeQName().getLocalPart())) {
+ mObj = new HexBinaryAdapter().marshal((byte[])mObj);
+ writeObject(marshaller, source, newJAXBElement(elName, String.class, mObj));
+ } else if (mObj instanceof JAXBElement) {
+ writeObject(marshaller, source, mObj);
+ } else if (marshaller.getSchema() != null) {
+ //force xsi:type so types can be validated instead of trying to
+ //use the RPC/lit element names that aren't in the schema
+ writeObject(marshaller, source, newJAXBElement(elName, Object.class, mObj));
+ } else {
+ writeObject(marshaller, source, newJAXBElement(elName, cls, mObj));
+ }
+ } else {
+ writeObject(marshaller, source, mObj);
+ }
+ } catch (Fault ex) {
+ throw ex;
+ } catch (javax.xml.bind.MarshalException ex) {
+ Message faultMessage = new Message("MARSHAL_ERROR", LOG, ex.getLinkedException()
+ .getMessage());
+ throw new Fault(faultMessage, ex);
+ } catch (Exception ex) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+ }
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private static JAXBElement<?> newJAXBElement(QName elName, Class<?> cls, Object mObj) {
+ if (mObj instanceof JAXBElement) {
+ return (JAXBElement)mObj;
+ }
+ if (cls == null && mObj != null) {
+ cls = mObj.getClass();
+ }
+ return new JAXBElement(elName, cls, mObj);
+ }
+
+ //TODO: cache the JAXBRIContext
+ public static void marshalWithBridge(QName qname,
+ Class<?> cls,
+ Annotation[] anns,
+ Set<Class<?>> ctxClasses,
+ Object elValue,
+ Object source, AttachmentMarshaller am) {
+ try {
+ JAXBUtils.BridgeWrapper bridge = JAXBUtils.createBridge(ctxClasses, qname, cls, anns);
+
+ if (source instanceof XMLStreamWriter) {
+ bridge.marshal(elValue, (XMLStreamWriter)source, am);
+ } else if (source instanceof OutputStream) {
+ //the namespace is missing when marshal the xsd:QName type
+ //to the OutputStream directly
+ java.io.StringWriter sw = new java.io.StringWriter();
+ StreamResult s1 = new StreamResult(sw);
+ bridge.marshal(elValue, s1);
+ ((OutputStream)source).write(sw.toString().getBytes());
+ } else if (source instanceof Node) {
+ bridge.marshal(elValue, (Node)source, am);
+ } else {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+ } catch (javax.xml.bind.MarshalException ex) {
+ Message faultMessage = new Message("MARSHAL_ERROR", LOG, ex.getLinkedException()
+ .getMessage());
+ throw new Fault(faultMessage, ex);
+ } catch (Exception ex) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+
+ }
+
+// TODO: cache the JAXBRIContext
+ public static Object unmarshalWithBridge(QName qname,
+ Class<?> cls,
+ Annotation[] anns,
+ Set<Class<?>> ctxClasses,
+ Object source,
+ AttachmentUnmarshaller am) {
+
+ try {
+ JAXBUtils.BridgeWrapper bridge = JAXBUtils.createBridge(ctxClasses, qname, cls, anns);
+
+ if (source instanceof XMLStreamReader) {
+ //DOMUtils.writeXml(StaxUtils.read((XMLStreamReader)source), System.out);
+ return bridge.unmarshal((XMLStreamReader)source, am);
+ } else if (source instanceof InputStream) {
+ return bridge.unmarshal((InputStream)source);
+ } else if (source instanceof Node) {
+ return bridge.unmarshal((Node)source, am);
+ } else {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+ } catch (javax.xml.bind.MarshalException ex) {
+ Message faultMessage = new Message("MARSHAL_ERROR", LOG, ex.getLinkedException()
+ .getMessage());
+ throw new Fault(faultMessage, ex);
+ } catch (Exception ex) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+
+ }
+
+ public static void marshallException(Marshaller marshaller, Exception elValue,
+ MessagePartInfo part, Object source) {
+ XMLStreamWriter writer = getStreamWriter(source);
+ QName qn = part.getElementQName();
+ try {
+ writer.writeStartElement("ns1", qn.getLocalPart(), qn.getNamespaceURI());
+ Class<?> cls = part.getTypeClass();
+ XmlAccessType accessType = Utils.getXmlAccessType(cls);
+ String namespace = part.getElementQName().getNamespaceURI();
+ String attNs = namespace;
+
+ SchemaInfo sch = part.getMessageInfo().getOperation().getInterface()
+ .getService().getSchema(namespace);
+ if (sch == null) {
+ LOG.warning("Schema associated with " + namespace + " is null");
+ namespace = null;
+ attNs = null;
+ } else {
+ if (!sch.isElementFormQualified()) {
+ namespace = null;
+ }
+ if (!sch.isAttributeFormQualified()) {
+ attNs = null;
+ }
+ }
+ List<Member> combinedMembers = new ArrayList<>();
+
+ for (Field f : Utils.getFields(cls, accessType)) {
+ XmlAttribute at = f.getAnnotation(XmlAttribute.class);
+ if (at == null) {
+ combinedMembers.add(f);
+ } else {
+ QName fname = new QName(attNs, StringUtils.isEmpty(at.name()) ? f.getName() : at.name());
+ ReflectionUtil.setAccessible(f);
+ Object o = Utils.getFieldValue(f, elValue);
+ DocumentFragment frag = DOMUtils.getEmptyDocument().createDocumentFragment();
+ writeObject(marshaller, frag, newJAXBElement(fname, String.class, o));
+
+ if (attNs != null) {
+ writer.writeAttribute(attNs, fname.getLocalPart(),
+ DOMUtils.getAllContent(frag));
+ } else {
+ writer.writeAttribute(fname.getLocalPart(), DOMUtils.getAllContent(frag));
+ }
+ }
+ }
+ for (Method m : Utils.getGetters(cls, accessType)) {
+ if (!m.isAnnotationPresent(XmlAttribute.class)) {
+ combinedMembers.add(m);
+ } else {
+ int idx = m.getName().startsWith("get") ? 3 : 2;
+ String name = m.getName().substring(idx);
+ name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ XmlAttribute at = m.getAnnotation(XmlAttribute.class);
+ QName mname = new QName(namespace, StringUtils.isEmpty(at.name()) ? name : at.name());
+ DocumentFragment frag = DOMUtils.getEmptyDocument().createDocumentFragment();
+ Object o = Utils.getMethodValue(m, elValue);
+ writeObject(marshaller, frag, newJAXBElement(mname, String.class, o));
+ if (attNs != null) {
+ writer.writeAttribute(attNs, mname.getLocalPart(),
+ DOMUtils.getAllContent(frag));
+ } else {
+ writer.writeAttribute(mname.getLocalPart(), DOMUtils.getAllContent(frag));
+ }
+ }
+ }
+
+ XmlAccessorOrder xmlAccessorOrder = cls.getAnnotation(XmlAccessorOrder.class);
+ if (xmlAccessorOrder != null && xmlAccessorOrder.value().equals(XmlAccessOrder.ALPHABETICAL)) {
+ Collections.sort(combinedMembers, new Comparator<Member>() {
+ public int compare(Member m1, Member m2) {
+ return m1.getName().compareTo(m2.getName());
+ }
+ });
+ }
+ XmlType xmlType = cls.getAnnotation(XmlType.class);
+ if (xmlType != null && xmlType.propOrder().length > 1 && !xmlType.propOrder()[0].isEmpty()) {
+ final List<String> orderList = Arrays.asList(xmlType.propOrder());
+ Collections.sort(combinedMembers, new Comparator<Member>() {
+ public int compare(Member m1, Member m2) {
+ String m1Name = getName(m1);
+ String m2Name = getName(m2);
+ int m1Index = orderList.indexOf(m1Name);
+ int m2Index = orderList.indexOf(m2Name);
+ if (m1Index != -1 && m2Index != -1) {
+ return m1Index - m2Index;
+ }
+ if (m1Index == -1 && m2Index != -1) {
+ return 1;
+ }
+ if (m1Index != -1 && m2Index == -1) {
+ return -1;
+ }
+ return 0;
+ }
+ });
+ }
+ for (Member member : combinedMembers) {
+ if (member instanceof Field) {
+ Field f = (Field)member;
+ QName fname = new QName(namespace, f.getName());
+ ReflectionUtil.setAccessible(f);
+ if (JAXBSchemaInitializer.isArray(f.getGenericType())) {
+ writeArrayObject(marshaller, writer, fname, f.get(elValue));
+ } else {
+ Object o = Utils.getFieldValue(f, elValue);
+ writeObject(marshaller, writer, newJAXBElement(fname, String.class, o));
+ }
+ } else { // it's a Method
+ Method m = (Method)member;
+ int idx = m.getName().startsWith("get") ? 3 : 2;
+ String name = m.getName().substring(idx);
+ name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ QName mname = new QName(namespace, name);
+ if (JAXBSchemaInitializer.isArray(m.getGenericReturnType())) {
+ writeArrayObject(marshaller, writer, mname, m.invoke(elValue));
+ } else {
+ Object o = Utils.getMethodValue(m, elValue);
+ writeObject(marshaller, writer, newJAXBElement(mname, String.class, o));
+ }
+ }
+ }
+
+ writer.writeEndElement();
+ writer.flush();
+ } catch (Exception e) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, e.getMessage()), e);
+ } finally {
+ StaxUtils.close(writer);
+ }
+ }
+
+ private static String getName(Member m1) {
+ final String m1Name;
+ if (m1 instanceof Field) {
+ m1Name = ((Field)m1).getName();
+ } else {
+ int idx = m1.getName().startsWith("get") ? 3 : 2;
+ String name = m1.getName().substring(idx);
+ m1Name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ }
+ return m1Name;
+ }
+ private static void writeArrayObject(Marshaller marshaller,
+ Object source,
+ QName mname,
+ Object mObj) throws Fault, JAXBException {
+ // Have to handle this ourselves.... which really
+ // sucks.... but what can we do?
+ if (mObj == null) {
+ return;
+ }
+ Object objArray;
+ final Class<?> cls;
+ if (mObj instanceof List) {
+ List<?> l = (List<?>)mObj;
+ objArray = l.toArray();
+ cls = null;
+ } else {
+ objArray = mObj;
+ cls = objArray.getClass().getComponentType();
+ }
+ int len = Array.getLength(objArray);
+ for (int x = 0; x < len; x++) {
+ Object o = Array.get(objArray, x);
+ writeObject(marshaller, source,
+ newJAXBElement(mname, cls == null ? o.getClass() : cls, o));
+ }
+ }
+
+ public static Exception unmarshallException(Unmarshaller u,
+ Object source,
+ MessagePartInfo part) {
+ XMLStreamReader reader;
+ if (source instanceof XMLStreamReader) {
+ reader = (XMLStreamReader)source;
+ } else if (source instanceof Element) {
+ reader = StaxUtils.createXMLStreamReader((Element)source);
+ try {
+ // advance into the node
+ reader.nextTag();
+ } catch (XMLStreamException e) {
+ // ignore
+ }
+ } else {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+ try {
+ QName qn = part.getElementQName();
+ if (!qn.equals(reader.getName())) {
+ throw new Fault(new Message("ELEMENT_NAME_MISMATCH", LOG, qn, reader.getName()));
+ }
+
+ Class<?> cls = part.getTypeClass();
+ Object obj;
+ try {
+ Constructor<?> cons = cls.getConstructor();
+ obj = cons.newInstance();
+ } catch (NoSuchMethodException nse) {
+ Constructor<?> cons = cls.getConstructor(new Class[] {String.class});
+ obj = cons.newInstance(new Object[1]);
+ }
+
+ XmlAccessType accessType = Utils.getXmlAccessType(cls);
+ reader.nextTag();
+ while (reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
+ QName q = reader.getName();
+ String fieldName = q.getLocalPart();
+ Field f = Utils.getField(cls, accessType, fieldName);
+ if (f != null) {
+ Type type = f.getGenericType();
+ ReflectionUtil.setAccessible(f);
+ if (JAXBSchemaInitializer.isArray(type)) {
+ Class<?> compType = JAXBSchemaInitializer.getArrayComponentType(type);
+ List<Object> ret = unmarshallArray(u, reader, q, compType, createList(type));
+ Object o = ret;
+ if (!isList(type)) {
+ if (compType.isPrimitive()) {
+ o = java.lang.reflect.Array.newInstance(compType, ret.size());
+ for (int x = 0; x < ret.size(); x++) {
+ Array.set(o, x, ret.get(x));
+ }
+ } else {
+ o = ret.toArray((Object[]) Array.newInstance(compType, ret.size()));
+ }
+ }
+
+ f.set(obj, o);
+ } else {
+ Object o = getElementValue(u.unmarshal(reader, Utils.getFieldType(f)));
+ Utils.setFieldValue(f, obj, o);
+ }
+ } else {
+ String s = StringUtils.capitalize(q.getLocalPart());
+ Method m = Utils.getMethod(cls, accessType, "get" + s);
+ if (m == null) {
+ m = Utils.getMethod(cls, accessType, "is" + s);
+ }
+ Type type = m.getGenericReturnType();
+ Object o;
+ if (JAXBSchemaInitializer.isArray(type)) {
+ Class<?> compType = JAXBSchemaInitializer
+ .getArrayComponentType(type);
+ List<Object> ret = unmarshallArray(u, reader,
+ q,
+ compType,
+ createList(type));
+ o = ret;
+ if (!isList(type)) {
+ if (compType.isPrimitive()) {
+ o = java.lang.reflect.Array.newInstance(compType, ret.size());
+ for (int x = 0; x < ret.size(); x++) {
+ Array.set(o, x, ret.get(x));
+ }
+ } else {
+ o = ret.toArray((Object[])Array.newInstance(compType, ret.size()));
+ }
+ }
+ } else {
+ o = getElementValue(u.unmarshal(reader, Utils.getMethodReturnType(m)));
+ }
+ Method m2 = Utils.getMethod(cls, accessType, "set" + s, m.getReturnType());
+ if (m2 != null) {
+ if (JAXBSchemaInitializer.isArray(type)) {
+ m2.invoke(obj, o);
+ } else {
+ Utils.setMethodValue(m, m2, obj, o);
+ }
+ } else {
+ Field fn = ReflectionUtil.getDeclaredField(cls, q.getLocalPart());
+ if (fn != null) {
+ ReflectionUtil.setAccessible(fn);
+ fn.set(obj, o);
+ }
+ }
+ }
+ if (reader.getEventType() == XMLStreamConstants.END_ELEMENT && q.equals(reader.getName())) {
+ reader.next();
+ }
+ }
+ return (Exception)obj;
+ } catch (Exception e) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, e.getMessage()), e);
+ }
+ }
+
+ private static void writeObject(Marshaller u, Object source, Object mObj) throws Fault, JAXBException {
+ if (source instanceof XMLStreamWriter) {
+ // allows the XML Stream Writer to adjust it's behaviour based on the state of the unmarshaller
+ if (source instanceof MarshallerAwareXMLWriter) {
+ ((MarshallerAwareXMLWriter) source).setMarshaller(u);
+ }
+ u.marshal(mObj, (XMLStreamWriter)source);
+ } else if (source instanceof OutputStream) {
+ u.marshal(mObj, (OutputStream)source);
+ } else if (source instanceof Node) {
+ u.marshal(mObj, (Node)source);
+ } else if (source instanceof XMLEventWriter) {
+ // allows the XML Event Writer to adjust it's behaviour based on the state of the unmarshaller
+ if (source instanceof MarshallerAwareXMLWriter) {
+ ((MarshallerAwareXMLWriter) source).setMarshaller(u);
+ }
+
+ u.marshal(mObj, (XMLEventWriter)source);
+ } else {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+ }
+
+ private static XMLStreamWriter getStreamWriter(Object source) throws Fault {
+ if (source instanceof XMLStreamWriter) {
+ return (XMLStreamWriter)source;
+ } else if (source instanceof OutputStream) {
+ return StaxUtils.createXMLStreamWriter((OutputStream)source);
+ } else if (source instanceof Node) {
+ return new W3CDOMStreamWriter((Element)source);
+ }
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+
+
+ public static void marshallNullElement(Marshaller marshaller,
+ Object source,
+ MessagePartInfo part) {
+ Class<?> clazz = part != null ? part.getTypeClass() : null;
+ try {
+ writeObject(marshaller, source, newJAXBElement(part.getElementQName(), clazz, null));
+ } catch (JAXBException e) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, e.getMessage()), e);
+ }
+ }
+
+
+ public static Object unmarshall(Unmarshaller u,
+ Object source,
+ MessagePartInfo part,
+ boolean unwrap) {
+ Class<?> clazz = part != null ? part.getTypeClass() : null;
+ if (clazz != null && Exception.class.isAssignableFrom(clazz)
+ && Boolean.TRUE.equals(part.getProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION"))) {
+ return unmarshallException(u, source, part);
+ }
+
+ QName elName = part != null ? part.getConcreteName() : null;
+ if (clazz != null && clazz.isArray()
+ && part.getXmlSchema() instanceof XmlSchemaElement) {
+ XmlSchemaElement el = (XmlSchemaElement)part.getXmlSchema();
+
+ if (el.getSchemaType() instanceof XmlSchemaSimpleType
+ && ((XmlSchemaSimpleType)el.getSchemaType()).getContent()
+ instanceof XmlSchemaSimpleTypeList) {
+
+ Object obj = unmarshall(u, source, elName, null, unwrap);
+ if (clazz.isArray() && obj instanceof List) {
+ return ((List<?>)obj).toArray((Object[])Array.newInstance(clazz.getComponentType(),
+ ((List<?>)obj).size()));
+ }
+
+ return obj;
+ } else if (part.getMessageInfo().getOperation().isUnwrapped() && el.getMaxOccurs() != 1) {
+ // must read ourselves....
+ List<Object> ret = unmarshallArray(u, source, elName, clazz.getComponentType(),
+ createList(part));
+ Object o = ret;
+ if (!isList(part)) {
+ if (isSet(part)) {
+ o = createSet(part, ret);
+ } else if (clazz.getComponentType().isPrimitive()) {
+ o = java.lang.reflect.Array.newInstance(clazz.getComponentType(), ret.size());
+ for (int x = 0; x < ret.size(); x++) {
+ Array.set(o, x, ret.get(x));
+ }
+ } else {
+ o = ret.toArray((Object[])Array.newInstance(clazz.getComponentType(), ret.size()));
+ }
+ }
+ return o;
+ }
+ } else if (byte[].class == clazz && part.getTypeQName() != null
+ && "hexBinary".equals(part.getTypeQName().getLocalPart())) {
+
+ String obj = (String)unmarshall(u, source, elName, String.class, unwrap);
+ return new HexBinaryAdapter().unmarshal(obj);
+ } else if (part != null && u.getSchema() != null
+ && !(part.getXmlSchema() instanceof XmlSchemaElement)) {
+ //Validating RPC/Lit, make sure we don't try a root element name thing
+ source = updateSourceWithXSIType(source, part.getTypeQName());
+ }
+
+ Object o = unmarshall(u, source, elName, clazz, unwrap);
+ if (o != null && o.getClass().isArray() && isList(part)) {
+ List<Object> ret = createList(part);
+ Collections.addAll(ret, (Object[])o);
+ o = ret;
+ }
+ return o;
+ }
+
+ private static Object updateSourceWithXSIType(Object source, final QName typeQName) {
+ if (source instanceof XMLStreamReader
+ && typeQName != null) {
+ XMLStreamReader reader = (XMLStreamReader)source;
+ String type = reader.getAttributeValue(Constants.URI_2001_SCHEMA_XSI, "type");
+ if (StringUtils.isEmpty(type)) {
+ source = new AddXSITypeStreamReader(reader, typeQName);
+ }
+ }
+ return source;
+ }
+
+ private static Object createSet(MessagePartInfo part, List<Object> ret) {
+ Type genericType = (Type)part.getProperty("generic.type");
+ Class<?> tp2 = (Class<?>)((ParameterizedType)genericType).getRawType();
+ if (tp2.isInterface()) {
+ return new HashSet<>(ret);
+ }
+ Collection<Object> c;
+ try {
+ c = CastUtils.cast((Collection<?>)tp2.newInstance());
+ } catch (Exception e) {
+ c = new HashSet<>();
+ }
+
+ c.addAll(ret);
+ return c;
+ }
+
+ private static boolean isSet(MessagePartInfo part) {
+ if (part.getTypeClass().isArray() && !part.getTypeClass().getComponentType().isPrimitive()) {
+ // && Collection.class.isAssignableFrom(part.getTypeClass())) {
+ // it's List Para
+ //
+ Type genericType = (Type)part.getProperty("generic.type");
+
+ if (genericType instanceof ParameterizedType) {
+ Type tp2 = ((ParameterizedType)genericType).getRawType();
+ if (tp2 instanceof Class) {
+ return Set.class.isAssignableFrom((Class<?>)tp2);
+ }
+ }
+ }
+ return false;
+ }
+
+ private static List<Object> createList(MessagePartInfo part) {
+ Type genericType = (Type)part.getProperty("generic.type");
+ return createList(genericType);
+ }
+ private static List<Object> createList(Type genericType) {
+ if (genericType instanceof ParameterizedType) {
+ Type tp2 = ((ParameterizedType)genericType).getRawType();
+ if (tp2 instanceof Class) {
+ Class<?> cls = (Class<?>)tp2;
+ if (!cls.isInterface() && List.class.isAssignableFrom(cls)) {
+ try {
+ return CastUtils.cast((List<?>)cls.newInstance());
+ } catch (Exception e) {
+ // ignore, just return an ArrayList
+ }
+ }
+ }
+ }
+ return new ArrayList<>();
+ }
+
+ private static boolean isList(Type cls) {
+ return cls instanceof ParameterizedType;
+ }
+ private static boolean isList(MessagePartInfo part) {
+ if (part.getTypeClass().isArray() && !part.getTypeClass().getComponentType().isPrimitive()) {
+ // && Collection.class.isAssignableFrom(part.getTypeClass())) {
+ // it's List Para
+ //
+ Type genericType = (Type)part.getProperty("generic.type");
+
+ if (genericType instanceof ParameterizedType) {
+ Type tp2 = ((ParameterizedType)genericType).getRawType();
+ if (tp2 instanceof Class) {
+ return List.class.isAssignableFrom((Class<?>)tp2);
+ }
+ }
+ }
+ return false;
+ }
+
+ private static Object doUnmarshal(final Unmarshaller u,
+ final Object source,
+ final QName elName,
+ final Class<?> clazz,
+ final boolean unwrap) throws Exception {
+
+ final Object obj;
+ boolean unmarshalWithClass = true;
+
+ if (clazz == null
+ || (!clazz.isPrimitive()
+ && !clazz.isArray()
+ && !clazz.isEnum()
+ && !clazz.equals(Calendar.class)
+ && (Modifier.isAbstract(clazz.getModifiers())
+ || Modifier.isInterface(clazz.getModifiers())))) {
+ unmarshalWithClass = false;
+ }
+
+ if (clazz != null
+ && ("javax.xml.datatype.XMLGregorianCalendar".equals(clazz.getName())
+ || "javax.xml.datatype.Duration".equals(clazz.getName()))) {
+ // special treat two jaxb defined built-in abstract types
+ unmarshalWithClass = true;
+ }
+ if (source instanceof Node) {
+ obj = unmarshalWithClass ? u.unmarshal((Node)source, clazz)
+ : u.unmarshal((Node)source);
+ } else if (source instanceof DepthXMLStreamReader) {
+ // JAXB optimizes a ton of stuff depending on the StreamReader impl. Thus,
+ // we REALLY want to pass the original reader in. This is OK with JAXB
+ // as it doesn't read beyond the end so the DepthXMLStreamReader state
+ // would be OK when it returns. The main winner is FastInfoset where parsing
+ // a testcase I have goes from about 300/sec to well over 1000.
+
+ DepthXMLStreamReader dr = (DepthXMLStreamReader)source;
+ XMLStreamReader reader = dr.getReader();
+
+ // allows the XML Stream Reader to adjust it's behaviour based on the state of the unmarshaller
+ if (reader instanceof UnmarshallerAwareXMLReader) {
+ ((UnmarshallerAwareXMLReader) reader).setUnmarshaller(u);
+ }
+
+ if (u.getSchema() != null) {
+ //validating, but we may need more namespaces
+ reader = findExtraNamespaces(reader);
+ }
+ obj = unmarshalWithClass ? u.unmarshal(reader, clazz) : u
+ .unmarshal(dr.getReader());
+ } else if (source instanceof XMLStreamReader) {
+ XMLStreamReader reader = (XMLStreamReader)source;
+
+ // allows the XML Stream Reader to adjust it's behaviour based on the state of the unmarshaller
+ if (reader instanceof UnmarshallerAwareXMLReader) {
+ ((UnmarshallerAwareXMLReader) reader).setUnmarshaller(u);
+ }
+
+ if (u.getSchema() != null) {
+ //validating, but we may need more namespaces
+ reader = findExtraNamespaces(reader);
+ }
+ obj = unmarshalWithClass ? u.unmarshal(reader, clazz) : u
+ .unmarshal(reader);
+ } else if (source instanceof XMLEventReader) {
+ // allows the XML Event Reader to adjust it's behaviour based on the state of the unmarshaller
+ if (source instanceof UnmarshallerAwareXMLReader) {
+ ((UnmarshallerAwareXMLReader) source).setUnmarshaller(u);
+ }
+
+ obj = unmarshalWithClass ? u.unmarshal((XMLEventReader)source, clazz) : u
+ .unmarshal((XMLEventReader)source);
+ } else if (source == null) {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, "null"));
+ } else {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+ return unwrap ? getElementValue(obj) : obj;
+ }
+ public static Object unmarshall(final Unmarshaller u,
+ final Object source,
+ final QName elName,
+ final Class<?> clazz,
+ final boolean unwrap) {
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ return doUnmarshal(u, source, elName, clazz, unwrap);
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ Exception ex = e.getException();
+ if (ex instanceof Fault) {
+ throw (Fault)ex;
+ }
+ if (ex instanceof javax.xml.bind.UnmarshalException) {
+ javax.xml.bind.UnmarshalException unmarshalEx = (javax.xml.bind.UnmarshalException)ex;
+ if (unmarshalEx.getLinkedException() != null) {
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG,
+ unmarshalEx.getLinkedException().getMessage()), ex);
+ }
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG,
+ unmarshalEx.getMessage()), ex);
+ }
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+ }
+
+ private static XMLStreamReader findExtraNamespaces(XMLStreamReader source) {
+ //due to a deficiency in the Stax API, there isn't a way to get all
+ //the namespace prefixes that are "valid" at this point. Thus, JAXB
+ //cannot set all the prefixes into the validator (which also doesn't allow
+ //setting a NSContext, just allows declaring of prefixes) so resolving
+ //prefixes and such will fail if they were declared on any of the parent
+ //elements.
+ //
+ //We'll use some reflection to grab the known namespaces from woodstox
+ //or the xerces parser and fake extra namespace decls on the root elements.
+ //slight performance penalty, but there already is a penalty if you are validating
+ //anyway.
+
+ NamespaceContext c = source.getNamespaceContext();
+ final Map<String, String> nsMap = new TreeMap<>();
+ try {
+ if (c instanceof W3CNamespaceContext) {
+ Element element = ((W3CNamespaceContext)c).getElement();
+ while (element != null) {
+ NamedNodeMap namedNodeMap = element.getAttributes();
+ for (int i = 0; i < namedNodeMap.getLength(); i++) {
+ Attr attr = (Attr)namedNodeMap.item(i);
+ if (attr.getPrefix() != null && "xmlns".equals(attr.getPrefix())) {
+ nsMap.put(attr.getLocalName(), attr.getValue());
+ }
+ }
+ element = (Element)element.getParentNode();
+ }
+ } else {
+ try {
+ //Woodstox version
+ c = (NamespaceContext)c.getClass().getMethod("createNonTransientNsContext",
+ Location.class)
+ .invoke(c, new Object[1]);
+ } catch (Throwable t) {
+ //ignore
+ }
+ Field f = ReflectionUtil.getDeclaredField(c.getClass(), "mNamespaces");
+ ReflectionUtil.setAccessible(f);
+ String[] ns = (String[])f.get(c);
+ for (int x = 0; x < ns.length; x += 2) {
+ if (ns[x] == null) {
+ nsMap.put("", ns[x + 1]);
+ } else {
+ nsMap.put(ns[x], ns[x + 1]);
+ }
+ }
+ }
+ } catch (Throwable t) {
+ //internal JDK/xerces version
+ try {
+ Field f = ReflectionUtil.getDeclaredField(c.getClass(), "fNamespaceContext");
+ ReflectionUtil.setAccessible(f);
+ Object c2 = f.get(c);
+ Enumeration<?> enm = (Enumeration<?>)c2.getClass().getMethod("getAllPrefixes").invoke(c2);
+ while (enm.hasMoreElements()) {
+ String s = (String)enm.nextElement();
+ if (s == null) {
+ nsMap.put("", c.getNamespaceURI(null));
+ } else {
+ nsMap.put(s, c.getNamespaceURI(s));
+ }
+ }
+ } catch (Throwable t2) {
+ //ignore
+ }
+ }
+ if (!nsMap.isEmpty()) {
+ for (int x = 0; x < source.getNamespaceCount(); x++) {
+ String pfx = source.getNamespacePrefix(x);
+ if (pfx == null) {
+ nsMap.remove("");
+ } else {
+ nsMap.remove(pfx);
+ }
+ }
+ if (!nsMap.isEmpty()) {
+ @SuppressWarnings("unchecked")
+ final Map.Entry<String, String>[] namespaces
+ = nsMap.entrySet().toArray(new Map.Entry[nsMap.size()]);
+ //OK. we have extra namespaces. We'll need to wrapper the reader
+ //with a new one that will fake extra namespace events
+ source = new DepthXMLStreamReader(source) {
+ public int getNamespaceCount() {
+ if (getDepth() == 0 && isStartElement()) {
+ return super.getNamespaceCount() + nsMap.size();
+ }
+ return super.getNamespaceCount();
+ }
+
+ public String getNamespacePrefix(int arg0) {
+ if (getDepth() == 0 && isStartElement()) {
+ int i = super.getNamespaceCount();
+ if (arg0 >= i) {
+ arg0 -= i;
+ return namespaces[arg0].getKey();
+ }
+ }
+ return super.getNamespacePrefix(arg0);
+ }
+
+ public String getNamespaceURI(int arg0) {
+ if (getDepth() == 0 && isStartElement()) {
+ int i = super.getNamespaceCount();
+ if (arg0 >= i) {
+ arg0 -= i;
+ return namespaces[arg0].getValue();
+ }
+ }
+ return super.getNamespaceURI(arg0);
+ }
+
+ };
+ }
+ }
+
+ return source;
+ }
+
+ public static Object getElementValue(Object obj) {
+ if (null == obj) {
+ return null;
+ }
+
+ if (obj instanceof JAXBElement) {
+ return ((JAXBElement<?>)obj).getValue();
+ }
+ return obj;
+ }
+
+ public static Class<?> getClassFromType(Type t) {
+ if (t instanceof Class) {
+ return (Class<?>)t;
+ } else if (t instanceof GenericArrayType) {
+ GenericArrayType g = (GenericArrayType)t;
+ return Array.newInstance(getClassFromType(g.getGenericComponentType()), 0).getClass();
+ } else if (t instanceof ParameterizedType) {
+ ParameterizedType p = (ParameterizedType)t;
+ return getClassFromType(p.getRawType());
+ }
+ // TypeVariable and WildCardType are not handled as it is unlikely such
+ // Types will
+ // JAXB Code Generated.
+ assert false;
+ throw new IllegalArgumentException("Cannot get Class object from unknown Type");
+ }
+
+ public static List<Object> unmarshallArray(Unmarshaller u, Object source,
+ QName elName, Class<?> clazz,
+ List<Object> ret) {
+ try {
+ XMLStreamReader reader;
+ if (source instanceof XMLStreamReader) {
+ reader = (XMLStreamReader)source;
+ } else if (source instanceof Element) {
+ reader = StaxUtils.createXMLStreamReader((Element)source);
+ } else {
+ throw new Fault(new Message("UNKNOWN_SOURCE", LOG, source.getClass().getName()));
+ }
+ while (reader.getName().equals(elName)) {
+ JAXBElement<?> type = u.unmarshal(reader, clazz);
+ if (type != null) {
+ ret.add(type.getValue());
+ }
+ while (reader.getEventType() != XMLStreamConstants.START_ELEMENT
+ && reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
+ reader.nextTag();
+ }
+ }
+ return ret;
+ } catch (Fault ex) {
+ throw ex;
+ } catch (javax.xml.bind.MarshalException ex) {
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG, ex.getLinkedException()
+ .getMessage()), ex);
+ } catch (Exception ex) {
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+ }
+}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
new file mode 100644
index 0000000..dde712f
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/JAXBSchemaInitializer.java
@@ -0,0 +1,823 @@
+/**
+ * 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.jaxb;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.annotation.XmlAccessOrder;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorOrder;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlList;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.jaxb.JAXBBeanInfo;
+import org.apache.cxf.common.jaxb.JAXBContextProxy;
+import org.apache.cxf.common.jaxb.JAXBUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.common.xmlschema.SchemaCollection;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.service.ServiceModelVisitor;
+import org.apache.cxf.service.model.FaultInfo;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.cxf.service.model.SchemaInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.cxf.wsdl.WSDLConstants;
+import org.apache.ws.commons.schema.XmlSchema;
+import org.apache.ws.commons.schema.XmlSchemaComplexType;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaForm;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.XmlSchemaSequenceMember;
+import org.apache.ws.commons.schema.XmlSchemaSimpleType;
+import org.apache.ws.commons.schema.XmlSchemaSimpleTypeList;
+import org.apache.ws.commons.schema.XmlSchemaType;
+import org.apache.ws.commons.schema.utils.NamespaceMap;
+
+/**
+ * Walks the service model and sets up the element/type names.
+ */
+class JAXBSchemaInitializer extends ServiceModelVisitor {
+ private static final Logger LOG = LogUtils.getLogger(JAXBSchemaInitializer.class);
+
+ private SchemaCollection schemas;
+ private JAXBContextProxy context;
+ private final boolean qualifiedSchemas;
+
+ JAXBSchemaInitializer(ServiceInfo serviceInfo,
+ SchemaCollection col,
+ JAXBContext context,
+ boolean q,
+ String defaultNs) {
+ super(serviceInfo);
+ schemas = col;
+ this.context = JAXBUtils.createJAXBContextProxy(context, serviceInfo.getXmlSchemaCollection(), defaultNs);
+ this.qualifiedSchemas = q;
+ }
+
+ static Class<?> getArrayComponentType(Type cls) {
+ if (cls instanceof Class) {
+ if (((Class<?>)cls).isArray()) {
+ return ((Class<?>)cls).getComponentType();
+ }
+ return (Class<?>)cls;
+ } else if (cls instanceof ParameterizedType) {
+ for (Type t2 : ((ParameterizedType)cls).getActualTypeArguments()) {
+ return getArrayComponentType(t2);
+ }
+ } else if (cls instanceof GenericArrayType) {
+ GenericArrayType gt = (GenericArrayType)cls;
+ Class<?> ct = (Class<?>) gt.getGenericComponentType();
+ return Array.newInstance(ct, 0).getClass();
+ }
+ return null;
+ }
+
+ public JAXBBeanInfo getBeanInfo(Type cls) {
+ if (cls instanceof Class) {
+ if (((Class<?>)cls).isArray()) {
+ return getBeanInfo(((Class<?>)cls).getComponentType());
+ }
+ return getBeanInfo((Class<?>)cls);
+ } else if (cls instanceof ParameterizedType) {
+ for (Type t2 : ((ParameterizedType)cls).getActualTypeArguments()) {
+ return getBeanInfo(t2);
+ }
+ } else if (cls instanceof GenericArrayType) {
+ GenericArrayType gt = (GenericArrayType)cls;
+ Class<?> ct = (Class<?>) gt.getGenericComponentType();
+ ct = Array.newInstance(ct, 0).getClass();
+
+ return getBeanInfo(ct);
+ }
+
+ return null;
+ }
+
+ public JAXBBeanInfo getBeanInfo(Class<?> cls) {
+ return getBeanInfo(context, cls);
+ }
+
+ public static JAXBBeanInfo getBeanInfo(JAXBContextProxy context, Class<?> cls) {
+ return JAXBUtils.getBeanInfo(context, cls);
+ }
+
+ @Override
+ public void begin(MessagePartInfo part) {
+ // Check to see if the WSDL information has been filled in for us.
+ if (part.getTypeQName() != null || part.getElementQName() != null) {
+ checkForExistence(part);
+ return;
+ }
+
+ Class<?> clazz = part.getTypeClass();
+ if (clazz == null) {
+ return;
+ }
+
+ boolean isFromWrapper = part.getMessageInfo().getOperation().isUnwrapped();
+ boolean isList = false;
+ if (clazz.isArray()) {
+ if (isFromWrapper && !Byte.TYPE.equals(clazz.getComponentType())) {
+ clazz = clazz.getComponentType();
+ } else if (!isFromWrapper) {
+ Annotation[] anns = (Annotation[])part.getProperty("parameter.annotations");
+ for (Annotation a : anns) {
+ if (a instanceof XmlList) {
+ part.setProperty("honor.jaxb.annotations", Boolean.TRUE);
+ clazz = clazz.getComponentType();
+ isList = true;
+ }
+ }
+ }
+ }
+
+ Annotation[] anns = (Annotation[])part.getProperty("parameter.annotations");
+ XmlJavaTypeAdapter jta = findFromTypeAdapter(context, clazz, anns);
+ JAXBBeanInfo jtaBeanInfo = null;
+ if (jta != null) {
+ jtaBeanInfo = findFromTypeAdapter(context, jta.value());
+ }
+ JAXBBeanInfo beanInfo = getBeanInfo(clazz);
+ if (jtaBeanInfo != beanInfo && jta != null) {
+ beanInfo = jtaBeanInfo;
+ if (anns == null) {
+ anns = new Annotation[] {jta};
+ } else {
+ boolean found = false;
+ for (Annotation t : anns) {
+ if (t == jta) {
+ found = true;
+ }
+ }
+ if (!found) {
+ Annotation[] tmp = new Annotation[anns.length + 1];
+ System.arraycopy(anns, 0, tmp, 0, anns.length);
+ tmp[anns.length] = jta;
+ anns = tmp;
+ }
+ }
+ part.setProperty("parameter.annotations", anns);
+ part.setProperty("honor.jaxb.annotations", Boolean.TRUE);
+ }
+ if (beanInfo == null) {
+ if (Exception.class.isAssignableFrom(clazz)) {
+ QName name = (QName)part.getMessageInfo().getProperty("elementName");
+ part.setElementQName(name);
+ buildExceptionType(part, clazz);
+ }
+ return;
+ }
+ boolean isElement = beanInfo.isElement()
+ && !Boolean.TRUE.equals(part.getMessageInfo().getOperation()
+ .getProperty("operation.force.types"));
+ boolean hasType = !beanInfo.getTypeNames().isEmpty();
+ if (isElement && isFromWrapper && hasType) {
+ //if there is both a Global element and a global type, AND we are in a wrapper,
+ //make sure we use the type instead of a ref to the element to
+ //match the rules for wrapped/unwrapped
+ isElement = false;
+ }
+
+ part.setElement(isElement);
+
+ if (isElement) {
+ QName name = new QName(beanInfo.getElementNamespaceURI(null),
+ beanInfo.getElementLocalName(null));
+ XmlSchemaElement el = schemas.getElementByQName(name);
+ if (el != null && el.getRef().getTarget() != null) {
+ part.setTypeQName(el.getRef().getTargetQName());
+ } else {
+ part.setElementQName(name);
+ }
+ part.setXmlSchema(el);
+ } else {
+ QName typeName = getTypeName(beanInfo);
+ if (typeName != null) {
+ XmlSchemaType type = schemas.getTypeByQName(typeName);
+ if (isList && type instanceof XmlSchemaSimpleType) {
+ XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType(type.getParent(), false);
+ XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
+ XmlSchemaSimpleType stype = (XmlSchemaSimpleType)type;
+ list.setItemTypeName(stype.getQName());
+ simpleType.setContent(list);
+ part.setXmlSchema(simpleType);
+ if (part.getConcreteName() == null) {
+ part.setConcreteName(new QName(null, part.getName().getLocalPart()));
+ }
+ } else {
+ part.setTypeQName(typeName);
+ part.setXmlSchema(type);
+ }
+ }
+ }
+ }
+
+ static XmlJavaTypeAdapter findFromTypeAdapter(JAXBContextProxy context, Class<?> clazz, Annotation[] anns) {
+ if (anns != null) {
+ for (Annotation a : anns) {
+ if (XmlJavaTypeAdapter.class.isAssignableFrom(a.annotationType())) {
+ JAXBBeanInfo ret = findFromTypeAdapter(context, ((XmlJavaTypeAdapter)a).value());
+ if (ret != null) {
+ return (XmlJavaTypeAdapter)a;
+ }
+ }
+ }
+ }
+ if (clazz != null) {
+ XmlJavaTypeAdapter xjta = clazz.getAnnotation(XmlJavaTypeAdapter.class);
+ if (xjta != null) {
+ JAXBBeanInfo ret = findFromTypeAdapter(context, xjta.value());
+ if (ret != null) {
+ return xjta;
+ }
+ }
+ }
+ return null;
+ }
+
+ static JAXBBeanInfo findFromTypeAdapter(JAXBContextProxy context,
+ @SuppressWarnings("rawtypes")
+ Class<? extends XmlAdapter> aclass) {
+ Class<?> c2 = aclass;
+ Type sp = c2.getGenericSuperclass();
+ while (!XmlAdapter.class.equals(c2) && c2 != null) {
+ sp = c2.getGenericSuperclass();
+ c2 = c2.getSuperclass();
+ }
+ if (sp instanceof ParameterizedType) {
+ Type tp = ((ParameterizedType)sp).getActualTypeArguments()[0];
+ if (tp instanceof Class) {
+ return getBeanInfo(context, (Class<?>)tp);
+ }
+ }
+ return null;
+ }
+
+ private QName getTypeName(JAXBBeanInfo beanInfo) {
+ Iterator<QName> itr = beanInfo.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return null;
+ }
+
+ return itr.next();
+ }
+ public void checkForExistence(MessagePartInfo part) {
+ QName qn = part.getElementQName();
+ if (qn != null) {
+ XmlSchemaElement el = schemas.getElementByQName(qn);
+ if (el == null) {
+ Class<?> clazz = part.getTypeClass();
+ if (clazz == null) {
+ return;
+ }
+
+ boolean isFromWrapper = part.getMessageInfo().getOperation().isUnwrapped();
+ if (isFromWrapper && clazz.isArray() && !Byte.TYPE.equals(clazz.getComponentType())) {
+ clazz = clazz.getComponentType();
+ }
+ JAXBBeanInfo beanInfo = getBeanInfo(clazz);
+ if (beanInfo == null) {
+ if (Exception.class.isAssignableFrom(clazz)) {
+ QName name = (QName)part.getMessageInfo().getProperty("elementName");
+ part.setElementQName(name);
+ buildExceptionType(part, clazz);
+ }
+ return;
+ }
+
+ QName typeName = getTypeName(beanInfo);
+
+ createBridgeXsElement(part, qn, typeName);
+ } else if (part.getXmlSchema() == null) {
+ part.setXmlSchema(el);
+ }
+ }
+ }
+
+ private void createBridgeXsElement(MessagePartInfo part, QName qn, QName typeName) {
+ SchemaInfo schemaInfo = serviceInfo.getSchema(qn.getNamespaceURI());
+ if (schemaInfo != null) {
+ XmlSchemaElement el = schemaInfo.getElementByQName(qn);
+ if (el == null) {
+ createXsElement(schemaInfo.getSchema(), part, typeName, schemaInfo);
+
+ } else if (!typeName.equals(el.getSchemaTypeName())) {
+ throw new Fault(new Message("CANNOT_CREATE_ELEMENT", LOG,
+ qn, typeName, el.getSchemaTypeName()));
+ }
+ return;
+ }
+
+ XmlSchema schema = schemas.newXmlSchemaInCollection(qn.getNamespaceURI());
+ if (qualifiedSchemas) {
+ schema.setElementFormDefault(XmlSchemaForm.QUALIFIED);
+ }
+ schemaInfo = new SchemaInfo(qn.getNamespaceURI(), qualifiedSchemas, false);
+ schemaInfo.setSchema(schema);
+
+ createXsElement(schema, part, typeName, schemaInfo);
+
+ NamespaceMap nsMap = new NamespaceMap();
+ nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, schema.getTargetNamespace());
+ nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD);
+ schema.setNamespaceContext(nsMap);
+
+ serviceInfo.addSchema(schemaInfo);
+ }
+
+ private XmlSchemaElement createXsElement(XmlSchema schema,
+ MessagePartInfo part,
+ QName typeName, SchemaInfo schemaInfo) {
+ XmlSchemaElement el = new XmlSchemaElement(schema, true);
+ el.setName(part.getElementQName().getLocalPart());
+ el.setNillable(true);
+ el.setSchemaTypeName(typeName);
+ part.setXmlSchema(el);
+ schemaInfo.setElement(null);
+ return el;
+ }
+
+ public void end(FaultInfo fault) {
+ MessagePartInfo part = fault.getFirstMessagePart();
+ Class<?> cls = part.getTypeClass();
+ Class<?> cl2 = (Class<?>)fault.getProperty(Class.class.getName());
+ if (cls != cl2) {
+ QName name = (QName)fault.getProperty("elementName");
+ part.setElementQName(name);
+ JAXBBeanInfo beanInfo = getBeanInfo(cls);
+ if (beanInfo == null) {
+ throw new Fault(new Message("NO_BEAN_INFO", LOG, cls.getName()));
+ }
+ SchemaInfo schemaInfo = serviceInfo.getSchema(part.getElementQName().getNamespaceURI());
+ if (schemaInfo != null
+ && !isExistSchemaElement(schemaInfo.getSchema(), part.getElementQName())) {
+
+ XmlSchemaElement el = new XmlSchemaElement(schemaInfo.getSchema(), true);
+ el.setName(part.getElementQName().getLocalPart());
+ el.setNillable(true);
+
+ schemaInfo.setElement(null);
+
+ Iterator<QName> itr = beanInfo.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ el.setSchemaTypeName(typeName);
+ }
+ } else if (part.getXmlSchema() == null) {
+ try {
+ cls.getConstructor(new Class[] {String.class});
+ } catch (Exception e) {
+ try {
+ cls.getConstructor(new Class[0]);
+ } catch (Exception e2) {
+ //no String or default constructor, we cannot use it
+ return;
+ }
+ }
+
+ //not mappable in JAXBContext directly, we'll have to do it manually :-(
+ SchemaInfo schemaInfo = serviceInfo.getSchema(part.getElementQName().getNamespaceURI());
+ if (schemaInfo == null
+ || isExistSchemaElement(schemaInfo.getSchema(), part.getElementQName())) {
+ return;
+ }
+
+ XmlSchemaElement el = new XmlSchemaElement(schemaInfo.getSchema(), true);
+ el.setName(part.getElementQName().getLocalPart());
+
+ schemaInfo.setElement(null);
+
+ part.setXmlSchema(el);
+
+ XmlSchemaComplexType ct = new XmlSchemaComplexType(schemaInfo.getSchema(), false);
+ el.setSchemaType(ct);
+ XmlSchemaSequence seq = new XmlSchemaSequence();
+ ct.setParticle(seq);
+
+ Method[] methods = cls.getMethods();
+ for (Method m : methods) {
+ if (m.getName().startsWith("get")
+ || m.getName().startsWith("is")) {
+ int beginIdx = m.getName().startsWith("get") ? 3 : 2;
+ try {
+ m.getDeclaringClass().getMethod("set" + m.getName().substring(beginIdx),
+ m.getReturnType());
+
+ JAXBBeanInfo beanInfo = getBeanInfo(m.getReturnType());
+ if (beanInfo != null) {
+ el = new XmlSchemaElement(schemaInfo.getSchema(), false);
+ el.setName(m.getName().substring(beginIdx));
+ Iterator<QName> itr = beanInfo.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ el.setSchemaTypeName(typeName);
+ }
+
+ seq.getItems().add(el);
+ } catch (Exception e) {
+ //not mappable
+ }
+ }
+ }
+ }
+ }
+
+
+ private void buildExceptionType(MessagePartInfo part, Class<?> cls) {
+ SchemaInfo schemaInfo = null;
+ for (SchemaInfo s : serviceInfo.getSchemas()) {
+ if (s.getNamespaceURI().equals(part.getElementQName().getNamespaceURI())) {
+ schemaInfo = s;
+ break;
+ }
+ }
+ XmlAccessorOrder xmlAccessorOrder = cls.getAnnotation(XmlAccessorOrder.class);
+ XmlType xmlTypeAnno = cls.getAnnotation(XmlType.class);
+ String[] propertyOrder = null;
+ boolean respectXmlTypeNS = false;
+ XmlSchema faultBeanSchema = null;
+ if (xmlTypeAnno != null && !StringUtils.isEmpty(xmlTypeAnno.namespace())
+ && !xmlTypeAnno.namespace().equals(part.getElementQName().getNamespaceURI())) {
+ respectXmlTypeNS = true;
+ NamespaceMap nsMap = new NamespaceMap();
+ nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, xmlTypeAnno.namespace());
+ nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD);
+
+ SchemaInfo faultBeanSchemaInfo = createSchemaIfNeeded(xmlTypeAnno.namespace(), nsMap);
+ faultBeanSchema = faultBeanSchemaInfo.getSchema();
+ }
+
+ if (xmlTypeAnno != null && xmlTypeAnno.propOrder().length > 0) {
+ propertyOrder = xmlTypeAnno.propOrder();
+ //TODO: handle @XmlAccessOrder
+ }
+
+ if (schemaInfo == null) {
+ NamespaceMap nsMap = new NamespaceMap();
+ nsMap.add(WSDLConstants.CONVENTIONAL_TNS_PREFIX, part.getElementQName().getNamespaceURI());
+ nsMap.add(WSDLConstants.NP_SCHEMA_XSD, WSDLConstants.NS_SCHEMA_XSD);
+ schemaInfo = createSchemaIfNeeded(part.getElementQName().getNamespaceURI(), nsMap);
+
+ }
+ XmlSchema schema = schemaInfo.getSchema();
+
+
+ // Before updating everything, make sure we haven't added this
+ // type yet. Multiple methods that throw the same exception
+ // types will cause duplicates.
+ String faultTypeName = xmlTypeAnno != null && !StringUtils.isEmpty(xmlTypeAnno.name())
+ ? xmlTypeAnno.name() : part.getElementQName().getLocalPart();
+ XmlSchemaType existingType = schema.getTypeByName(faultTypeName);
+ if (existingType != null) {
+ return;
+ }
+
+ XmlSchemaElement el = new XmlSchemaElement(schema, true);
+ el.setName(part.getElementQName().getLocalPart());
+ part.setXmlSchema(el);
+ schemaInfo.setElement(null);
+
+ if (respectXmlTypeNS) {
+ schema = faultBeanSchema; //create complexType in the new created schema for xmlType
+ }
+
+ XmlSchemaComplexType ct = new XmlSchemaComplexType(schema, true);
+ ct.setName(faultTypeName);
+
+ el.setSchemaTypeName(ct.getQName());
+
+ XmlSchemaSequence seq = new XmlSchemaSequence();
+ ct.setParticle(seq);
+ String namespace = part.getElementQName().getNamespaceURI();
+ XmlAccessType accessType = Utils.getXmlAccessType(cls);
+//
+ for (Field f : Utils.getFields(cls, accessType)) {
+ //map field
+ Type type = Utils.getFieldType(f);
+ //we want to return the right type for collections so if we get null
+ //from the return type we check if it's ParameterizedType and get the
+ //generic return type.
+ if ((type == null) && (f.getGenericType() instanceof ParameterizedType)) {
+ type = f.getGenericType();
+ }
+ if (generateGenericType(type)) {
+ buildGenericElements(schema, seq, f);
+ } else {
+ JAXBBeanInfo beanInfo = getBeanInfo(type);
+ if (beanInfo != null) {
+ XmlElement xmlElementAnno = f.getAnnotation(XmlElement.class);
+ addElement(schema, seq, beanInfo, new QName(namespace, f.getName()), isArray(type), xmlElementAnno);
+ }
+ }
+ }
+ for (Method m : Utils.getGetters(cls, accessType)) {
+ //map method
+ Type type = Utils.getMethodReturnType(m);
+ // we want to return the right type for collections so if we get null
+ // from the return type we check if it's ParameterizedType and get the
+ // generic return type.
+ if ((type == null) && (m.getGenericReturnType() instanceof ParameterizedType)) {
+ type = m.getGenericReturnType();
+ }
+
+ if (generateGenericType(type)) {
+ buildGenericElements(schema, seq, m, type);
+ } else {
+ JAXBBeanInfo beanInfo = getBeanInfo(type);
+ if (beanInfo != null) {
+ int idx = m.getName().startsWith("get") ? 3 : 2;
+ String name = m.getName().substring(idx);
+ name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ XmlElement xmlElementAnno = m.getAnnotation(XmlElement.class);
+ addElement(schema, seq, beanInfo, new QName(namespace, name), isArray(type), xmlElementAnno);
+ }
+ }
+ }
+ // Create element in xsd:sequence for Exception.class
+ if (Exception.class.isAssignableFrom(cls)) {
+ addExceptionMessage(cls, schema, seq);
+ }
+
+ if (propertyOrder != null) {
+ if (propertyOrder.length == seq.getItems().size()) {
+ sortItems(seq, propertyOrder);
+ } else if (propertyOrder.length > 1
+ || (propertyOrder.length == 1 && !propertyOrder[0].isEmpty())) {
+ LOG.log(Level.WARNING, "propOrder in @XmlType doesn't define all schema elements :"
+ + Arrays.toString(propertyOrder));
+ }
+ }
+
+ if (xmlAccessorOrder != null && xmlAccessorOrder.value().equals(XmlAccessOrder.ALPHABETICAL)
+ && propertyOrder == null) {
+ sort(seq);
+ }
+
+ schemas.addCrossImports();
+ part.setProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION", Boolean.TRUE);
+ }
+ private void addExceptionMessage(Class<?> cls, XmlSchema schema, XmlSchemaSequence seq) {
+ try {
+ //a subclass could mark the message method as transient
+ Method m = cls.getMethod("getMessage");
+ if (!m.isAnnotationPresent(XmlTransient.class)
+ && m.getDeclaringClass().equals(Throwable.class)) {
+ JAXBBeanInfo beanInfo = getBeanInfo(java.lang.String.class);
+ XmlSchemaElement exEle = new XmlSchemaElement(schema, false);
+ exEle.setName("message");
+ exEle.setSchemaTypeName(getTypeName(beanInfo));
+ exEle.setMinOccurs(0);
+ seq.getItems().add(exEle);
+ }
+ } catch (Exception e) {
+ //ignore, just won't have the message element
+ }
+ }
+
+ private boolean generateGenericType(Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType paramType = (ParameterizedType)type;
+ if (paramType.getActualTypeArguments().length > 1) {
+ return true;
+
+ }
+ }
+ return false;
+ }
+
+ private void buildGenericElements(XmlSchema schema, XmlSchemaSequence seq, Field f) {
+ XmlSchemaComplexType generics = new XmlSchemaComplexType(schema, true);
+ Type type = f.getGenericType();
+ String rawType = ((ParameterizedType)type).getRawType().toString();
+ String typeName = StringUtils.uncapitalize(rawType.substring(rawType.lastIndexOf('.') + 1));
+ generics.setName(typeName);
+
+ Class<?> genericsClass = f.getType();
+ buildGenericSeq(schema, generics, genericsClass);
+
+ String name = Character.toLowerCase(f.getName().charAt(0)) + f.getName().substring(1);
+ XmlSchemaElement newel = new XmlSchemaElement(schema, false);
+ newel.setName(name);
+ newel.setSchemaTypeName(generics.getQName());
+ newel.setMinOccurs(0);
+ if (!seq.getItems().contains(newel)) {
+ seq.getItems().add(newel);
+ }
+ }
+
+ private void buildGenericElements(XmlSchema schema, XmlSchemaSequence seq, Method m, Type type) {
+ String rawType = ((ParameterizedType)type).getRawType().toString();
+ String typeName = StringUtils.uncapitalize(rawType.substring(rawType.lastIndexOf('.') + 1));
+
+ XmlSchemaComplexType generics = (XmlSchemaComplexType)schema.getTypeByName(typeName);
+ if (generics == null) {
+ generics = new XmlSchemaComplexType(schema, true);
+ generics.setName(typeName);
+ }
+
+ Class<?> genericsClass = m.getReturnType();
+ buildGenericSeq(schema, generics, genericsClass);
+
+ int idx = m.getName().startsWith("get") ? 3 : 2;
+ String name = m.getName().substring(idx);
+ name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
+ XmlSchemaElement newel = new XmlSchemaElement(schema, false);
+ newel.setName(name);
+ newel.setSchemaTypeName(generics.getQName());
+ newel.setMinOccurs(0);
+ if (!seq.getItems().contains(newel)) {
+ seq.getItems().add(newel);
+ }
+ }
+
+ private void buildGenericSeq(XmlSchema schema, XmlSchemaComplexType generics, Class<?> genericsClass) {
+ XmlSchemaSequence genericsSeq = new XmlSchemaSequence();
+ generics.setParticle(genericsSeq);
+ XmlAccessType accessType = Utils.getXmlAccessType(genericsClass);
+
+ for (Field f : Utils.getFields(genericsClass, accessType)) {
+ if (f.getGenericType() instanceof TypeVariable) {
+ String genericName = Character.toLowerCase(f.getName().charAt(0)) + f.getName().substring(1);
+ XmlSchemaElement genericEle = new XmlSchemaElement(schema, false);
+ genericEle.setName(genericName);
+ genericEle.setMinOccurs(0);
+ JAXBBeanInfo anyBean = getBeanInfo(context, f.getType());
+ Iterator<QName> itr = anyBean.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ genericEle.setSchemaTypeName(typeName);
+ genericsSeq.getItems().add(genericEle);
+ }
+ }
+
+ for (Method genericMethod : Utils.getGetters(genericsClass, accessType)) {
+ if (genericMethod.getGenericReturnType() instanceof TypeVariable) {
+ int idx = genericMethod.getName().startsWith("get") ? 3 : 2;
+ String genericName = genericMethod.getName().substring(idx);
+ genericName = Character.toLowerCase(genericName.charAt(0)) + genericName.substring(1);
+ XmlSchemaElement genericEle = new XmlSchemaElement(schema, false);
+ genericEle.setName(genericName);
+ genericEle.setMinOccurs(0);
+ JAXBBeanInfo anyBean = getBeanInfo(context, genericMethod.getReturnType());
+ Iterator<QName> itr = anyBean.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ genericEle.setSchemaTypeName(typeName);
+ genericsSeq.getItems().add(genericEle);
+ }
+
+ }
+ }
+
+
+ static boolean isArray(Type cls) {
+ if (cls instanceof Class) {
+ return ((Class<?>)cls).isArray();
+ } else if (cls instanceof ParameterizedType) {
+ ParameterizedType pt = (ParameterizedType)cls;
+ return pt.getActualTypeArguments().length == 1
+ && pt.getRawType() instanceof Class
+ && Collection.class.isAssignableFrom((Class<?>)pt.getRawType());
+ } else if (cls instanceof GenericArrayType) {
+ return true;
+ }
+ return false;
+ }
+
+ protected void addElement(XmlSchema schema,
+ XmlSchemaSequence seq, JAXBBeanInfo beanInfo,
+ QName name, boolean isArray, XmlElement xmlElementAnno) {
+ XmlSchemaElement el = new XmlSchemaElement(schema, false);
+ if (isArray) {
+ el.setMinOccurs(0);
+ el.setMaxOccurs(Long.MAX_VALUE);
+ } else {
+ if (xmlElementAnno == null) {
+ el.setMinOccurs(0);
+ el.setNillable(false);
+ } else {
+ el.setNillable(xmlElementAnno.nillable());
+ int minOccurs = xmlElementAnno.required() ? 1 : 0;
+ el.setMinOccurs(minOccurs);
+ }
+ }
+
+ if (beanInfo.isElement()) {
+ QName ename = new QName(beanInfo.getElementNamespaceURI(null),
+ beanInfo.getElementLocalName(null));
+ XmlSchemaElement el2 = schemas.getElementByQName(ename);
+ el.setNillable(false);
+ el.getRef().setTargetQName(el2.getQName());
+ } else {
+ if (xmlElementAnno != null && !StringUtils.isEmpty(xmlElementAnno.name())) {
+ el.setName(xmlElementAnno.name());
+ } else {
+ el.setName(name.getLocalPart());
+ }
+ Iterator<QName> itr = beanInfo.getTypeNames().iterator();
+ if (!itr.hasNext()) {
+ return;
+ }
+ QName typeName = itr.next();
+ el.setSchemaTypeName(typeName);
+ }
+
+ seq.getItems().add(el);
+ }
+
+ private SchemaInfo createSchemaIfNeeded(String namespace, NamespaceMap nsMap) {
+ SchemaInfo schemaInfo = serviceInfo.getSchema(namespace);
+ if (schemaInfo == null) {
+ XmlSchema xmlSchema = schemas.newXmlSchemaInCollection(namespace);
+
+ if (qualifiedSchemas) {
+ xmlSchema.setElementFormDefault(XmlSchemaForm.QUALIFIED);
+ }
+
+ xmlSchema.setNamespaceContext(nsMap);
+
+ schemaInfo = new SchemaInfo(namespace);
+ schemaInfo.setSchema(xmlSchema);
+ serviceInfo.addSchema(schemaInfo);
+ }
+ return schemaInfo;
+ }
+
+ private boolean isExistSchemaElement(XmlSchema schema, QName qn) {
+ return schema.getElementByName(qn) != null;
+ }
+
+ private void sortItems(final XmlSchemaSequence seq, final String[] propertyOrder) {
+ final List<String> propList = Arrays.asList(propertyOrder);
+ Collections.sort(seq.getItems(), new Comparator<XmlSchemaSequenceMember>() {
+ public int compare(XmlSchemaSequenceMember o1, XmlSchemaSequenceMember o2) {
+ XmlSchemaElement element1 = (XmlSchemaElement)o1;
+ XmlSchemaElement element2 = (XmlSchemaElement)o2;
+ int index1 = propList.indexOf(element1.getName());
+ int index2 = propList.indexOf(element2.getName());
+ return index1 - index2;
+ }
+
+ });
+ }
+ //sort to Alphabetical order
+ private void sort(final XmlSchemaSequence seq) {
+ Collections.sort(seq.getItems(), new Comparator<XmlSchemaSequenceMember>() {
+ public int compare(XmlSchemaSequenceMember o1, XmlSchemaSequenceMember o2) {
+ XmlSchemaElement element1 = (XmlSchemaElement)o1;
+ XmlSchemaElement element2 = (XmlSchemaElement)o2;
+ return element1.getName().compareTo(element2.getName());
+ }
+
+ });
+ }
+
+}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/io/DataReaderImpl.java b/transform/src/patch/java/org/apache/cxf/jaxb/io/DataReaderImpl.java
new file mode 100644
index 0000000..ef8a15b
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/io/DataReaderImpl.java
@@ -0,0 +1,207 @@
+/**
+ * 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.jaxb.io;
+
+import java.lang.annotation.Annotation;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.PropertyException;
+import javax.xml.bind.UnmarshalException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.ValidationEvent;
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.jaxb.JAXBUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.databinding.DataReader;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.jaxb.JAXBDataBase;
+import org.apache.cxf.jaxb.JAXBDataBinding;
+import org.apache.cxf.jaxb.JAXBEncoderDecoder;
+import org.apache.cxf.jaxb.UnmarshallerEventHandler;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.service.model.MessagePartInfo;
+
+public class DataReaderImpl<T> extends JAXBDataBase implements DataReader<T> {
+ private static final Logger LOG = LogUtils.getLogger(JAXBDataBinding.class);
+ JAXBDataBinding databinding;
+ boolean unwrapJAXBElement;
+ ValidationEventHandler veventHandler;
+ boolean setEventHandler = true;
+
+ public DataReaderImpl(JAXBDataBinding binding, boolean unwrap) {
+ super(binding.getContext());
+ unwrapJAXBElement = unwrap;
+ databinding = binding;
+ }
+
+ public Object read(T input) {
+ return read(null, input);
+ }
+
+ private static class WSUIDValidationHandler implements ValidationEventHandler {
+ ValidationEventHandler origHandler;
+ WSUIDValidationHandler(ValidationEventHandler o) {
+ origHandler = o;
+ }
+
+ public boolean handleEvent(ValidationEvent event) {
+ // if the original handler has already handled the event, no need for us
+ // to do anything, otherwise if not yet handled, then do this 'hack'
+ if (origHandler != null && origHandler.handleEvent(event)) {
+ return true;
+ }
+ // hack for CXF-3453
+ String msg = event.getMessage();
+ return msg != null
+ && msg.contains(":Id")
+ && (msg.startsWith("cvc-type.3.1.1")
+ || msg.startsWith("cvc-type.3.2.2")
+ || msg.startsWith("cvc-complex-type.3.1.1")
+ || msg.startsWith("cvc-complex-type.3.2.2"));
+ }
+ }
+
+ public void setProperty(String prop, Object value) {
+ if (prop.equals(JAXBDataBinding.UNWRAP_JAXB_ELEMENT)) {
+ unwrapJAXBElement = Boolean.TRUE.equals(value);
+ } else if (prop.equals(org.apache.cxf.message.Message.class.getName())) {
+ org.apache.cxf.message.Message m = (org.apache.cxf.message.Message)value;
+ veventHandler = getValidationEventHandler(m, JAXBDataBinding.READER_VALIDATION_EVENT_HANDLER);
+ if (veventHandler == null) {
+ veventHandler = databinding.getValidationEventHandler();
+ }
+ setEventHandler = MessageUtils.getContextualBoolean(m,
+ JAXBDataBinding.SET_VALIDATION_EVENT_HANDLER, true);
+
+ Object unwrapProperty = m.get(JAXBDataBinding.UNWRAP_JAXB_ELEMENT);
+ if (unwrapProperty == null) {
+ unwrapProperty = m.getExchange().get(JAXBDataBinding.UNWRAP_JAXB_ELEMENT);
+ }
+ if (unwrapProperty != null) {
+ unwrapJAXBElement = Boolean.TRUE.equals(unwrapProperty);
+ }
+ }
+ }
+
+ private Unmarshaller createUnmarshaller() {
+ try {
+ Unmarshaller um = context.createUnmarshaller();
+ if (databinding.getUnmarshallerListener() != null) {
+ um.setListener(databinding.getUnmarshallerListener());
+ }
+ if (setEventHandler) {
+ um.setEventHandler(new WSUIDValidationHandler(veventHandler));
+ }
+ if (databinding.getUnmarshallerProperties() != null) {
+ for (Map.Entry<String, Object> propEntry
+ : databinding.getUnmarshallerProperties().entrySet()) {
+ try {
+ um.setProperty(propEntry.getKey(), propEntry.getValue());
+ } catch (PropertyException pe) {
+ LOG.log(Level.INFO, "PropertyException setting Marshaller properties", pe);
+ }
+ }
+ }
+ um.setSchema(schema);
+ um.setAttachmentUnmarshaller(getAttachmentUnmarshaller());
+ for (XmlAdapter<?, ?> adapter : databinding.getConfiguredXmlAdapters()) {
+ um.setAdapter(adapter);
+ }
+ return um;
+ } catch (javax.xml.bind.UnmarshalException ex) {
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG, ex.getLinkedException()
+ .getMessage()), ex);
+ } catch (JAXBException ex) {
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+ }
+
+ public Object read(MessagePartInfo part, T reader) {
+ boolean honorJaxbAnnotation = honorJAXBAnnotations(part);
+ if (honorJaxbAnnotation) {
+ Annotation[] anns = getJAXBAnnotation(part);
+ if (anns.length > 0) {
+ // RpcLit will use the JAXB Bridge to unmarshall part message when it is
+ // annotated with @XmlList,@XmlAttachmentRef,@XmlJavaTypeAdapter
+ // TODO:Cache the JAXBRIContext
+ QName qname = new QName(null, part.getConcreteName().getLocalPart());
+
+ Object obj = JAXBEncoderDecoder.unmarshalWithBridge(qname,
+ part.getTypeClass(),
+ anns,
+ databinding.getContextClasses(),
+ reader,
+ getAttachmentUnmarshaller());
+
+ onCompleteUnmarshalling();
+
+ return obj;
+ }
+ }
+
+ Unmarshaller um = createUnmarshaller();
+ try {
+ Object obj = JAXBEncoderDecoder.unmarshall(um, reader, part,
+ unwrapJAXBElement);
+ onCompleteUnmarshalling();
+
+ return obj;
+ } finally {
+ JAXBUtils.closeUnmarshaller(um);
+ }
+ }
+
+ public Object read(QName name, T input, Class<?> type) {
+ Unmarshaller um = createUnmarshaller();
+
+ try {
+ Object obj = JAXBEncoderDecoder.unmarshall(um, input,
+ name, type,
+ unwrapJAXBElement);
+ onCompleteUnmarshalling();
+
+ return obj;
+ } finally {
+ JAXBUtils.closeUnmarshaller(um);
+ }
+
+ }
+
+ private void onCompleteUnmarshalling() {
+ if (setEventHandler && veventHandler instanceof UnmarshallerEventHandler) {
+ try {
+ ((UnmarshallerEventHandler) veventHandler).onUnmarshalComplete();
+ } catch (UnmarshalException e) {
+ if (e.getLinkedException() != null) {
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG,
+ e.getLinkedException().getMessage()), e);
+ }
+ throw new Fault(new Message("UNMARSHAL_ERROR", LOG, e.getMessage()), e);
+ }
+ }
+ }
+}
diff --git a/transform/src/patch/java/org/apache/cxf/jaxb/io/DataWriterImpl.java b/transform/src/patch/java/org/apache/cxf/jaxb/io/DataWriterImpl.java
new file mode 100644
index 0000000..c7de57f
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxb/io/DataWriterImpl.java
@@ -0,0 +1,321 @@
+/**
+ * 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.jaxb.io;
+
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.MarshalException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.PropertyException;
+import javax.xml.bind.ValidationEvent;
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.attachment.AttachmentMarshaller;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.jaxb.JAXBUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.ReflectionUtil;
+import org.apache.cxf.databinding.DataWriter;
+import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.jaxb.JAXBDataBase;
+import org.apache.cxf.jaxb.JAXBDataBinding;
+import org.apache.cxf.jaxb.JAXBEncoderDecoder;
+import org.apache.cxf.jaxb.MarshallerEventHandler;
+import org.apache.cxf.jaxb.attachment.JAXBAttachmentMarshaller;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.service.model.MessagePartInfo;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+
+public class DataWriterImpl<T> extends JAXBDataBase implements DataWriter<T> {
+ private static final Logger LOG = LogUtils.getLogger(JAXBDataBinding.class);
+
+ ValidationEventHandler veventHandler;
+ boolean setEventHandler = true;
+ boolean noEscape;
+ private JAXBDataBinding databinding;
+ private Bus bus;
+
+ public DataWriterImpl(Bus bus, JAXBDataBinding binding) {
+ this(bus, binding, false);
+ }
+ public DataWriterImpl(Bus bus, JAXBDataBinding binding, boolean noEsc) {
+ super(binding.getContext());
+ databinding = binding;
+ noEscape = noEsc;
+ this.bus = bus;
+ }
+
+ public void write(Object obj, T output) {
+ write(obj, null, output);
+ }
+
+ public void setProperty(String prop, Object value) {
+ if (prop.equals(org.apache.cxf.message.Message.class.getName())) {
+ org.apache.cxf.message.Message m = (org.apache.cxf.message.Message)value;
+ veventHandler = getValidationEventHandler(m, JAXBDataBinding.WRITER_VALIDATION_EVENT_HANDLER);
+ if (veventHandler == null) {
+ veventHandler = databinding.getValidationEventHandler();
+ }
+ setEventHandler = MessageUtils.getContextualBoolean(m,
+ JAXBDataBinding.SET_VALIDATION_EVENT_HANDLER, true);
+ }
+ }
+
+ private static class MtomValidationHandler implements ValidationEventHandler {
+ ValidationEventHandler origHandler;
+ JAXBAttachmentMarshaller marshaller;
+ MtomValidationHandler(ValidationEventHandler v,
+ JAXBAttachmentMarshaller m) {
+ origHandler = v;
+ marshaller = m;
+ }
+
+ public boolean handleEvent(ValidationEvent event) {
+ // CXF-1194/CXF-7438 this hack is specific to MTOM, so pretty safe to leave in
+ // here before calling the origHandler.
+ String msg = event.getMessage();
+ if ((msg.startsWith("cvc-type.3.1.2") || msg.startsWith("cvc-complex-type.2.2"))
+ && msg.contains(marshaller.getLastMTOMElementName().getLocalPart())) {
+ return true;
+ }
+
+ if (origHandler != null) {
+ return origHandler.handleEvent(event);
+ }
+ return false;
+ }
+
+ }
+
+ public Marshaller createMarshaller(Object elValue, MessagePartInfo part) {
+ //Class<?> cls = null;
+ //if (part != null) {
+ // cls = part.getTypeClass();
+ //}
+ //
+ //if (cls == null) {
+ // cls = null != elValue ? elValue.getClass() : null;
+ //}
+ //
+ //if (cls != null && cls.isArray() && elValue instanceof Collection) {
+ // Collection<?> col = (Collection<?>)elValue;
+ // elValue = col.toArray((Object[])Array.newInstance(cls.getComponentType(), col.size()));
+ //}
+ Marshaller marshaller;
+ try {
+
+ marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, StandardCharsets.UTF_8.name());
+ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
+ marshaller.setListener(databinding.getMarshallerListener());
+ databinding.applyEscapeHandler(!noEscape, eh -> JAXBUtils.setEscapeHandler(marshaller, eh));
+
+ if (setEventHandler) {
+ ValidationEventHandler h = veventHandler;
+ if (veventHandler == null) {
+ h = new ValidationEventHandler() {
+ public boolean handleEvent(ValidationEvent event) {
+ //continue on warnings only
+ return event.getSeverity() == ValidationEvent.WARNING;
+ }
+ };
+ }
+ marshaller.setEventHandler(h);
+ }
+
+ final Map<String, String> nspref = databinding.getDeclaredNamespaceMappings();
+ final Map<String, String> nsctxt = databinding.getContextualNamespaceMap();
+ // set the prefix mapper if either of the prefix map is configured
+ if (nspref != null || nsctxt != null) {
+ Object mapper = JAXBUtils.setNamespaceMapper(bus, nspref != null ? nspref : nsctxt, marshaller);
+ if (nsctxt != null) {
+ setContextualNamespaceDecls(mapper, nsctxt);
+ }
+ }
+ if (databinding.getMarshallerProperties() != null) {
+ for (Map.Entry<String, Object> propEntry
+ : databinding.getMarshallerProperties().entrySet()) {
+ try {
+ marshaller.setProperty(propEntry.getKey(), propEntry.getValue());
+ } catch (PropertyException pe) {
+ LOG.log(Level.INFO, "PropertyException setting Marshaller properties", pe);
+ }
+ }
+ }
+
+ marshaller.setSchema(schema);
+ AttachmentMarshaller atmarsh = getAttachmentMarshaller();
+ marshaller.setAttachmentMarshaller(atmarsh);
+
+ if (schema != null
+ && atmarsh instanceof JAXBAttachmentMarshaller) {
+ //we need a special even handler for XOP attachments
+ marshaller.setEventHandler(new MtomValidationHandler(marshaller.getEventHandler(),
+ (JAXBAttachmentMarshaller)atmarsh));
+ }
+ } catch (javax.xml.bind.MarshalException ex) {
+ Message faultMessage = new Message("MARSHAL_ERROR", LOG, ex.getLinkedException()
+ .getMessage());
+ throw new Fault(faultMessage, ex);
+ } catch (JAXBException ex) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, ex.getMessage()), ex);
+ }
+ for (XmlAdapter<?, ?> adapter : databinding.getConfiguredXmlAdapters()) {
+ marshaller.setAdapter(adapter);
+ }
+ return marshaller;
+ }
+
+ //REVISIT should this go into JAXBUtils?
+ private static void setContextualNamespaceDecls(Object mapper, Map<String, String> nsctxt) {
+ try {
+ Method m = ReflectionUtil.getDeclaredMethod(mapper.getClass(),
+ "setContextualNamespaceDecls", new Class<?>[]{String[].class});
+ String[] args = new String[nsctxt.size() * 2];
+ int ai = 0;
+ for (Entry<String, String> nsp : nsctxt.entrySet()) {
+ args[ai++] = nsp.getValue();
+ args[ai++] = nsp.getKey();
+ }
+ m.invoke(mapper, new Object[]{args});
+ } catch (Exception e) {
+ // ignore
+ LOG.log(Level.WARNING, "Failed to set the contextual namespace map", e);
+ }
+
+ }
+
+ public void write(Object obj, MessagePartInfo part, T output) {
+ boolean honorJaxbAnnotation = honorJAXBAnnotations(part);
+ if (part != null && !part.isElement() && part.getTypeClass() != null) {
+ honorJaxbAnnotation = true;
+ }
+ checkPart(part, obj);
+
+ if (obj != null
+ || !(part.getXmlSchema() instanceof XmlSchemaElement)) {
+
+ if (obj instanceof Exception
+ && part != null
+ && Boolean.TRUE.equals(part.getProperty(JAXBDataBinding.class.getName()
+ + ".CUSTOM_EXCEPTION"))) {
+ JAXBEncoderDecoder.marshallException(createMarshaller(obj, part),
+ (Exception)obj,
+ part,
+ output);
+ onCompleteMarshalling();
+ } else {
+ Annotation[] anns = getJAXBAnnotation(part);
+ if (!honorJaxbAnnotation || anns.length == 0) {
+ JAXBEncoderDecoder.marshall(createMarshaller(obj, part), obj, part, output);
+ onCompleteMarshalling();
+ } else if (honorJaxbAnnotation && anns.length > 0) {
+ //RpcLit will use the JAXB Bridge to marshall part message when it is
+ //annotated with @XmlList,@XmlAttachmentRef,@XmlJavaTypeAdapter
+ //TODO:Cache the JAXBRIContext
+
+ JAXBEncoderDecoder.marshalWithBridge(part.getConcreteName(),
+ part.getTypeClass(),
+ anns,
+ databinding.getContextClasses(),
+ obj,
+ output,
+ getAttachmentMarshaller());
+ }
+ }
+ } else if (needToRender(part)) {
+ JAXBEncoderDecoder.marshallNullElement(createMarshaller(null, part),
+ output, part);
+
+ onCompleteMarshalling();
+ }
+ }
+
+ private void checkPart(MessagePartInfo part, Object object) {
+ if (part == null || part.getTypeClass() == null || object == null) {
+ return;
+ }
+ Class<?> typeClass = part.getTypeClass();
+ if (typeClass == null) {
+ return;
+ }
+ if (typeClass.isPrimitive()) {
+ if (typeClass == Long.TYPE) {
+ typeClass = Long.class;
+ } else if (typeClass == Integer.TYPE) {
+ typeClass = Integer.class;
+ } else if (typeClass == Short.TYPE) {
+ typeClass = Short.class;
+ } else if (typeClass == Byte.TYPE) {
+ typeClass = Byte.class;
+ } else if (typeClass == Character.TYPE) {
+ typeClass = Character.class;
+ } else if (typeClass == Double.TYPE) {
+ typeClass = Double.class;
+ } else if (typeClass == Float.TYPE) {
+ typeClass = Float.class;
+ } else if (typeClass == Boolean.TYPE) {
+ typeClass = Boolean.class;
+ }
+ } else if (typeClass.isArray() && object instanceof Collection) {
+ //JAXB allows a pseudo [] <--> List equivalence
+ return;
+ }
+ if (!typeClass.isInstance(object)) {
+ throw new IllegalArgumentException("Part " + part.getName() + " should be of type "
+ + typeClass.getName() + ", not "
+ + object.getClass().getName());
+ }
+ }
+
+ private boolean needToRender(MessagePartInfo part) {
+ if (part != null && part.getXmlSchema() instanceof XmlSchemaElement) {
+ XmlSchemaElement element = (XmlSchemaElement)part.getXmlSchema();
+ return element.isNillable() && element.getMinOccurs() > 0;
+ }
+ return false;
+ }
+
+ private void onCompleteMarshalling() {
+ if (setEventHandler && veventHandler instanceof MarshallerEventHandler) {
+ try {
+ ((MarshallerEventHandler) veventHandler).onMarshalComplete();
+ } catch (MarshalException e) {
+ if (e.getLinkedException() != null) {
+ throw new Fault(new Message("MARSHAL_ERROR", LOG,
+ e.getLinkedException().getMessage()), e);
+ }
+ throw new Fault(new Message("MARSHAL_ERROR", LOG, e.getMessage()), e);
+ }
+ }
+ }
+}