cxf-rt-databinding-jaxb changes since 3.4.3
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);
+            }
+        }
+    }
+}