You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by db...@apache.org on 2021/05/01 07:59:34 UTC

[tomee-jakarta] branch master updated: TOMEE-3188 jaxrs.spec.provider.standardnotnull clientJaxbProviderTest

This is an automated email from the ASF dual-hosted git repository.

dblevins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomee-jakarta.git


The following commit(s) were added to refs/heads/master by this push:
     new e1733c7  TOMEE-3188 jaxrs.spec.provider.standardnotnull clientJaxbProviderTest
e1733c7 is described below

commit e1733c7252146c5380bb442c44ef4760bc6de6fd
Author: David Blevins <da...@gmail.com>
AuthorDate: Sat May 1 00:58:44 2021 -0700

    TOMEE-3188 jaxrs.spec.provider.standardnotnull clientJaxbProviderTest
---
 .../cxf/jaxrs/provider/AbstractJAXBProvider.java   | 993 +++++++++++++++++++++
 1 file changed, 993 insertions(+)

diff --git a/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java b/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java
new file mode 100644
index 0000000..b94760a
--- /dev/null
+++ b/transform/src/patch/java/org/apache/cxf/jaxrs/provider/AbstractJAXBProvider.java
@@ -0,0 +1,993 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.jaxrs.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Type;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NoContentException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.PropertyException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.ValidationEventHandler;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.validation.Schema;
+
+import org.w3c.dom.Element;
+
+import org.xml.sax.helpers.DefaultHandler;
+
+import com.ctc.wstx.exc.WstxEOFException;
+
+import org.apache.cxf.annotations.SchemaValidation;
+import org.apache.cxf.common.jaxb.JAXBUtils;
+import org.apache.cxf.common.util.PackageUtils;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.utils.ExceptionUtils;
+import org.apache.cxf.jaxrs.utils.InjectionUtils;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.apache.cxf.jaxrs.utils.schemas.SchemaHandler;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.staxutils.DepthExceededStaxException;
+import org.apache.cxf.staxutils.DepthRestrictingStreamReader;
+import org.apache.cxf.staxutils.DepthXMLStreamReader;
+import org.apache.cxf.staxutils.DocumentDepthProperties;
+import org.apache.cxf.staxutils.StaxUtils;
+import org.apache.cxf.staxutils.transform.TransformUtils;
+
+public abstract class AbstractJAXBProvider<T> extends AbstractConfigurableProvider
+    implements MessageBodyReader<T>, MessageBodyWriter<T> {
+
+    protected static final String NS_MAPPER_PROPERTY_RI = "com.sun.xml.bind.namespacePrefixMapper";
+    protected static final String NS_MAPPER_PROPERTY_RI_INT = "com.sun.xml.internal.bind.namespacePrefixMapper";
+    private static final String JAXB_DEFAULT_NAMESPACE = "##default";
+    private static final String JAXB_DEFAULT_NAME = "##default";
+    private static final Set<Class<?>> UNSUPPORTED_CLASSES = 
+        new HashSet<Class<?>>(Arrays.asList(InputStream.class,
+                                            OutputStream.class,
+                                            StreamingOutput.class));
+    protected Set<Class<?>> collectionContextClasses = ConcurrentHashMap.newKeySet();
+
+    protected Map<String, String> jaxbElementClassMap = Collections.emptyMap();
+    protected boolean unmarshalAsJaxbElement;
+    protected boolean marshalAsJaxbElement;
+    protected boolean xmlTypeAsJaxbElementOnly;
+
+    protected Map<String, String> outElementsMap;
+    protected Map<String, String> outAppendMap;
+    protected List<String> outDropElements;
+    protected List<String> inDropElements;
+    protected Map<String, String> inElementsMap;
+    protected Map<String, String> inAppendMap;
+    protected Map<String, JAXBContext> packageContexts = new ConcurrentHashMap<>();
+    protected Map<Class<?>, JAXBContext> classContexts = new ConcurrentHashMap<>();
+    private boolean attributesToElements;
+
+    private MessageContext mc;
+
+    private Schema schema;
+    private String catalogLocation;
+    private Map<String, SchemaHandler> schemaHandlers;
+
+    private String collectionWrapperName;
+    private Map<String, String> collectionWrapperMap;
+    private List<String> jaxbElementClassNames;
+    private boolean xmlRootAsJaxbElement;
+    private Map<String, Object> cProperties;
+    private Map<String, Object> uProperties;
+
+    private boolean skipJaxbChecks;
+    private boolean singleJaxbContext;
+    private boolean useSingleContextForPackages;
+
+    private Class<?>[] extraClass;
+
+    private boolean validateInputIfPossible = true;
+    private boolean validateOutputIfPossible;
+    private boolean validateBeforeWrite;
+    private ValidationEventHandler eventHandler;
+    private Unmarshaller.Listener unmarshallerListener;
+    private Marshaller.Listener marshallerListener;
+    private DocumentDepthProperties depthProperties;
+    private String namespaceMapperPropertyName;
+
+    private static JAXBContext newJAXBContextInstance(Class<?>[] classes, Map<String, Object> cProperties) 
+        throws JAXBException {
+
+        try {
+            return AccessController.doPrivileged((PrivilegedExceptionAction<JAXBContext>)() -> {
+                return JAXBContext.newInstance(classes, cProperties);
+            });
+        } catch (PrivilegedActionException e) {
+            Throwable t = e.getCause();
+            if (t instanceof JAXBException) {
+                throw (JAXBException) t;
+            }
+            throw new RuntimeException(t);
+        }
+    }
+
+    public void setXmlRootAsJaxbElement(boolean xmlRootAsJaxbElement) {
+        this.xmlRootAsJaxbElement = xmlRootAsJaxbElement;
+    }
+
+
+    protected void setNamespaceMapper(Marshaller ms,
+                                      Map<String, String> map) throws Exception {
+        Object nsMapper = JAXBUtils.setNamespaceMapper(getBus(), map, ms);
+        if (nsMapper != null && namespaceMapperPropertyName != null) {
+            setMarshallerProp(ms, nsMapper, namespaceMapperPropertyName, null);
+        }
+    }
+
+    protected static void setMarshallerProp(Marshaller ms, Object value,
+                                          String name1, String name2) throws Exception {
+        try {
+            ms.setProperty(name1, value);
+        } catch (PropertyException ex) {
+            if (name2 != null) {
+                ms.setProperty(name2, value);
+            } else {
+                throw ex;
+            }
+        }
+
+    }
+
+    public void setValidationHandler(ValidationEventHandler handler) {
+        eventHandler = handler;
+    }
+
+    public void setSingleJaxbContext(boolean useSingleContext) {
+        singleJaxbContext = useSingleContext;
+    }
+
+    public void setUseSingleContextForPackages(boolean use) {
+        useSingleContextForPackages = use;
+    }
+
+    public void setExtraClass(Class<?>[] userExtraClass) {
+        extraClass = userExtraClass;
+    }
+
+    @Override
+    public void init(List<ClassResourceInfo> cris) {
+        if (singleJaxbContext) {
+            JAXBContext context = null;
+            Set<Class<?>> allTypes = null;
+            if (cris != null) {
+                allTypes = new HashSet<>(ResourceUtils.getAllRequestResponseTypes(cris, true)
+                    .getAllTypes().keySet());
+                context = org.apache.cxf.jaxrs.utils.JAXBUtils.createJaxbContext(allTypes, extraClass, cProperties);
+            } else if (extraClass != null) {
+                allTypes = new HashSet<>(Arrays.asList(extraClass));
+                context = org.apache.cxf.jaxrs.utils.JAXBUtils.createJaxbContext(allTypes, null, cProperties);
+            }
+
+            if (context != null) {
+                for (Class<?> cls : allTypes) {
+                    if (useSingleContextForPackages) {
+                        packageContexts.put(PackageUtils.getPackageName(cls), context);
+                    } else {
+                        classContexts.put(cls, context);
+                    }
+                }
+            }
+        }
+        if (cris != null) {
+            List<String> schemaLocs = new LinkedList<>();
+            SchemaValidation sv = null;
+            for (ClassResourceInfo cri : cris) {
+                sv = cri.getServiceClass().getAnnotation(SchemaValidation.class);
+                if (sv != null && sv.schemas() != null && sv.type() != SchemaValidation.SchemaValidationType.NONE) {
+                    for (String s : sv.schemas()) {
+                        String theSchema = s;
+                        if (!theSchema.startsWith("classpath:")) {
+                            theSchema = "classpath:" + theSchema;
+                        }
+                        schemaLocs.add(theSchema);
+                    }
+                }
+            }
+            if (!schemaLocs.isEmpty()) {
+                this.setSchemaLocations(schemaLocs);
+                if (cris.isEmpty() && schema != null && sv != null) {
+                    SchemaValidation.SchemaValidationType type = sv.type();
+                    if (type == SchemaValidation.SchemaValidationType.OUT) {
+                        validateInputIfPossible = false;
+                        validateOutputIfPossible = true;
+                    } else if (type == SchemaValidation.SchemaValidationType.BOTH) {
+                        validateOutputIfPossible = true;
+                    }
+                }
+            }
+        }
+    }
+
+    public void setContextProperties(Map<String, Object> contextProperties) {
+        cProperties = contextProperties;
+    }
+
+    public void setUnmarshallerProperties(Map<String, Object> unmarshalProperties) {
+        uProperties = unmarshalProperties;
+    }
+
+    public void setUnmarshallAsJaxbElement(boolean value) {
+        unmarshalAsJaxbElement = value;
+    }
+
+    public void setMarshallAsJaxbElement(boolean value) {
+        marshalAsJaxbElement = value;
+    }
+
+    public void setXmlTypeAsJaxbElementOnly(boolean value) {
+        this.xmlTypeAsJaxbElementOnly = value;
+    }
+
+    public void setJaxbElementClassNames(List<String> names) {
+        jaxbElementClassNames = names;
+    }
+
+    public void setJaxbElementClassMap(Map<String, String> map) {
+        jaxbElementClassMap = map;
+    }
+
+    protected <X> X getStreamHandlerFromCurrentMessage(Class<X> staxCls) {
+        Message m = PhaseInterceptorChain.getCurrentMessage();
+        if (m != null) {
+            return staxCls.cast(m.getContent(staxCls));
+        }
+        return null;
+    }
+
+    protected boolean isXmlRoot(Class<?> cls) {
+        return cls.getAnnotation(XmlRootElement.class) != null;
+    }
+
+    protected boolean isXmlType(Class<?> cls) {
+        return cls.getAnnotation(XmlType.class) != null;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected Object convertToJaxbElementIfNeeded(Object obj, Class<?> cls, Type genericType)
+        throws Exception {
+
+        Class<?> jaxbElementCls = jaxbElementClassNames == null ? null : getJaxbElementClass(cls);
+        boolean asJaxbElement = jaxbElementCls != null;
+        if (!asJaxbElement && isXmlRoot(cls) && !xmlRootAsJaxbElement) {
+            return obj;
+        }
+        if (jaxbElementCls == null) {
+            jaxbElementCls = cls;
+        }
+        QName name = null;
+        String expandedName = jaxbElementClassMap.get(jaxbElementCls.getName());
+        if (expandedName != null) {
+            name = JAXRSUtils.convertStringToQName(expandedName);
+        } else if (marshalAsJaxbElement || asJaxbElement) {
+            name = getJaxbQName(jaxbElementCls, genericType, obj, false);
+        }
+        return name != null ? new JAXBElement<Object>(name, (Class)jaxbElementCls, null, obj) : obj;
+    }
+
+    protected Class<?> getJaxbElementClass(Class<?> cls) {
+        if (cls == Object.class) {
+            return null;
+        }
+        if (jaxbElementClassNames.contains(cls.getName())) {
+            return cls;
+        }
+        return getJaxbElementClass(cls.getSuperclass());
+
+    }
+
+    public void setCollectionWrapperName(String wName) {
+        collectionWrapperName = wName;
+    }
+
+    public void setCollectionWrapperMap(Map<String, String> map) {
+        collectionWrapperMap = map;
+    }
+
+    protected void setContext(MessageContext context) {
+        mc = context;
+    }
+
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] anns, MediaType mt) {
+
+        if (InjectionUtils.isSupportedCollectionOrArray(type)) {
+            type = InjectionUtils.getActualType(genericType);
+            if (type == null) {
+                return false;
+            }
+        }
+        return marshalAsJaxbElement && (!xmlTypeAsJaxbElementOnly || isXmlType(type))
+            || isSupported(type, genericType, anns);
+    }
+    public void writeTo(T t, Type genericType, Annotation[] annotations,
+                 MediaType mediaType,
+                 MultivaluedMap<String, Object> httpHeaders,
+                 OutputStream entityStream) throws IOException, WebApplicationException {
+        @SuppressWarnings("unchecked")
+        Class<T> type = (Class<T>)t.getClass();
+        writeTo(t, type, genericType, annotations, mediaType, httpHeaders, entityStream);
+    }
+
+    protected JAXBContext getCollectionContext(Class<?> type) throws JAXBException {
+        if (collectionContextClasses.add(type)) {
+            collectionContextClasses.add(CollectionWrapper.class);
+        }
+        return newJAXBContextInstance(
+            collectionContextClasses.toArray(new Class[0]), cProperties);
+    }
+
+    protected QName getCollectionWrapperQName(Class<?> cls, Type type, Object object, boolean pluralName)
+        throws Exception {
+        String name = getCollectionWrapperName(cls);
+        if (name == null) {
+            return getJaxbQName(cls, type, object, pluralName);
+        }
+
+        return JAXRSUtils.convertStringToQName(name);
+    }
+
+    private String getCollectionWrapperName(Class<?> cls) {
+        if (collectionWrapperName != null) {
+            return collectionWrapperName;
+        }
+        if (collectionWrapperMap != null) {
+            return collectionWrapperMap.get(cls.getName());
+        }
+
+        return null;
+    }
+
+    protected QName getJaxbQName(Class<?> cls, Type type, Object object, boolean pluralName)
+        throws Exception {
+
+        if (cls == JAXBElement.class) {
+            return object != null ? ((JAXBElement<?>)object).getName() : null;
+        }
+
+        XmlRootElement root = cls.getAnnotation(XmlRootElement.class);
+        if (root != null) {
+            return getQNameFromNamespaceAndName(root.namespace(), root.name(), cls, pluralName);
+        } else if (isXmlType(cls)) {
+            XmlType xmlType = cls.getAnnotation(XmlType.class);
+            return getQNameFromNamespaceAndName(xmlType.namespace(), xmlType.name(), cls, pluralName);
+        } else {
+            return new QName(getPackageNamespace(cls), cls.getSimpleName());
+        }
+    }
+
+    private static QName getQNameFromNamespaceAndName(String ns, String localName, Class<?> cls, boolean plural) {
+        String name = getLocalName(localName, cls.getSimpleName(), plural);
+        String namespace = getNamespace(ns);
+        if ("".equals(namespace)) {
+            namespace = getPackageNamespace(cls);
+        }
+        return new QName(namespace, name);
+    }
+
+    private static String getLocalName(String name, String clsName, boolean pluralName) {
+        if (JAXB_DEFAULT_NAME.equals(name)) {
+            name = clsName;
+            if (name.length() > 1) {
+                name = name.substring(0, 1).toLowerCase() + name.substring(1);
+            } else {
+                name = name.toLowerCase();
+            }
+        }
+        if (pluralName) {
+            name += 's';
+        }
+        return name;
+    }
+
+    private static String getPackageNamespace(Class<?> cls) {
+        String packageNs = JAXBUtils.getPackageNamespace(cls);
+        return packageNs != null ? getNamespace(packageNs) : "";
+    }
+
+    private static String getNamespace(String namespace) {
+        if (JAXB_DEFAULT_NAMESPACE.equals(namespace)) {
+            return "";
+        }
+        return namespace;
+    }
+
+    public boolean isReadable(Class<?> type, Type genericType, Annotation[] anns, MediaType mt) {
+        if (InjectionUtils.isSupportedCollectionOrArray(type)) {
+            type = InjectionUtils.getActualType(genericType);
+            if (type == null) {
+                return false;
+            }
+        }
+        return canBeReadAsJaxbElement(type) || isSupported(type, genericType, anns);
+    }
+
+    protected boolean canBeReadAsJaxbElement(Class<?> type) {
+        return unmarshalAsJaxbElement && type != Response.class;
+    }
+
+    public void setSchemaLocations(List<String> locations) {
+        schema = SchemaHandler.createSchema(locations, catalogLocation, getBus());
+    }
+
+    public void setCatalogLocation(String name) {
+        this.catalogLocation = name;
+    }
+
+    public void setSchemaHandler(SchemaHandler handler) {
+        setSchema(handler.getSchema());
+    }
+
+    public void setSchemaHandlers(Map<String, SchemaHandler> handlers) {
+        schemaHandlers = handlers;
+    }
+
+    protected void setSchema(Schema s) {
+        schema = s;
+    }
+
+    public long getSize(T o, Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {
+        return -1;
+    }
+
+    protected MessageContext getContext() {
+        return mc;
+    }
+
+    @SuppressWarnings("unchecked")
+    public JAXBContext getJAXBContext(Class<?> type, Type genericType) throws JAXBException {
+        if (mc != null) {
+            ContextResolver<JAXBContext> resolver =
+                mc.getResolver(ContextResolver.class, JAXBContext.class);
+            if (resolver != null) {
+                JAXBContext customContext = resolver.getContext(type);
+                if (customContext != null) {
+                    return customContext;
+                }
+            }
+        }
+
+        JAXBContext context = classContexts.get(type);
+        if (context != null) {
+            return context;
+        }
+
+        context = getPackageContext(type, genericType);
+
+        return context != null ? context : getClassContext(type, genericType);
+    }
+    public JAXBContext getClassContext(Class<?> type) throws JAXBException {
+        return getClassContext(type, type);
+    }
+    protected JAXBContext getClassContext(Class<?> type, Type genericType) throws JAXBException {
+        final JAXBException[] jaxbException = new JAXBException[] {null};
+        final JAXBContext context = classContexts.computeIfAbsent(type, t -> {
+            final Class<?>[] classes;
+            if (extraClass != null) {
+                classes = new Class[extraClass.length + 1];
+                classes[0] = type;
+                System.arraycopy(extraClass, 0, classes, 1, extraClass.length);
+            } else {
+                classes = new Class[] {type};
+            }
+
+            try {
+                return newJAXBContextInstance(classes, cProperties);
+            } catch (JAXBException e) {
+                jaxbException[0] = e;
+                return null;
+            }
+        });
+        if (null != jaxbException[0]) {
+            throw jaxbException[0];
+        }
+        return context;
+    }
+    public JAXBContext getPackageContext(Class<?> type) {
+        return getPackageContext(type, type);
+    }
+    protected JAXBContext getPackageContext(final Class<?> type, Type genericType) {
+        if (type == null || type == JAXBElement.class) {
+            return null;
+        }
+        final String packageName = PackageUtils.getPackageName(type);
+        return packageContexts.computeIfAbsent(packageName, p -> {
+            try {
+                final ClassLoader loader = AccessController.doPrivileged((PrivilegedAction<ClassLoader>) 
+                    () -> {
+                        return type.getClassLoader();
+                    });
+                if (loader != null && objectFactoryOrIndexAvailable(type)) {
+
+                    String contextName = packageName;
+                    if (extraClass != null) {
+                        StringBuilder sb = new StringBuilder(contextName);
+                        for (Class<?> extra : extraClass) {
+                            String extraPackage = PackageUtils.getPackageName(extra);
+                            if (!extraPackage.equals(packageName)) {
+                                sb.append(':').append(extraPackage);
+                            }
+                        }
+                        contextName = sb.toString();
+                    }
+
+                    return JAXBContext.newInstance(contextName, loader, cProperties);
+                }
+            } catch (JAXBException ex) {
+                LOG.fine("Error creating a JAXBContext using ObjectFactory : "
+                            + ex.getMessage());
+            }
+            return null;
+        });
+    }
+
+    protected boolean isSupported(Class<?> type, Type genericType, Annotation[] anns) {
+        if (jaxbElementClassMap != null && jaxbElementClassMap.containsKey(type.getName())
+            || isSkipJaxbChecks()) {
+            return true;
+        }
+        if (UNSUPPORTED_CLASSES.contains(type)) {
+            return false;
+        }
+        return isXmlRoot(type)
+            || JAXBElement.class.isAssignableFrom(type)
+            || objectFactoryOrIndexAvailable(type)
+            || (type != genericType && objectFactoryForType(genericType))
+            || org.apache.cxf.jaxrs.utils.JAXBUtils.getAdapter(type, anns) != null;
+
+    }
+
+    protected boolean objectFactoryOrIndexAvailable(Class<?> type) {
+        return type.getResource("ObjectFactory.class") != null
+               || type.getResource("jaxb.index") != null;
+    }
+
+    private boolean objectFactoryForType(Type genericType) {
+        return objectFactoryOrIndexAvailable(InjectionUtils.getActualType(genericType));
+    }
+
+    protected Unmarshaller createUnmarshaller(Class<?> cls, Type genericType)
+        throws JAXBException {
+        return createUnmarshaller(cls, genericType, false);
+    }
+
+    protected Unmarshaller createUnmarshaller(Class<?> cls, Type genericType, boolean isCollection)
+        throws JAXBException {
+        JAXBContext context = isCollection ? getCollectionContext(cls)
+                                           : getJAXBContext(cls, genericType);
+        Unmarshaller unmarshaller = context.createUnmarshaller();
+        if (validateInputIfPossible) {
+            Schema theSchema = getSchema(cls);
+            if (theSchema != null) {
+                unmarshaller.setSchema(theSchema);
+            }
+        }
+        if (eventHandler != null) {
+            unmarshaller.setEventHandler(eventHandler);
+        }
+        if (unmarshallerListener != null) {
+            unmarshaller.setListener(unmarshallerListener);
+        }
+        if (uProperties != null) {
+            for (Map.Entry<String, Object> entry : uProperties.entrySet()) {
+                unmarshaller.setProperty(entry.getKey(), entry.getValue());
+            }
+        }
+        return unmarshaller;
+    }
+
+    protected Marshaller createMarshaller(Object obj, Class<?> cls, Type genericType, String enc)
+        throws JAXBException {
+
+        Class<?> objClazz = JAXBElement.class.isAssignableFrom(cls)
+                            ? ((JAXBElement<?>)obj).getDeclaredType() : cls;
+
+        JAXBContext context = getJAXBContext(objClazz, genericType);
+        Marshaller marshaller = context.createMarshaller();
+        if (enc != null) {
+            marshaller.setProperty(Marshaller.JAXB_ENCODING, enc);
+        }
+        if (marshallerListener != null) {
+            marshaller.setListener(marshallerListener);
+        }
+        validateObjectIfNeeded(marshaller, cls, obj);
+        return marshaller;
+    }
+
+    protected void validateObjectIfNeeded(Marshaller marshaller, Class<?> cls, Object obj)
+        throws JAXBException {
+        if (validateOutputIfPossible) {
+            Schema theSchema = getSchema(cls);
+            if (theSchema != null) {
+                marshaller.setEventHandler(eventHandler);
+                marshaller.setSchema(theSchema);
+                if (validateBeforeWrite) {
+                    marshaller.marshal(obj, new DefaultHandler());
+                    marshaller.setSchema(null);
+                }
+            }
+        }
+    }
+
+    protected Class<?> getActualType(Class<?> type, Type genericType, Annotation[] anns) {
+        Class<?> theType;
+        if (JAXBElement.class.isAssignableFrom(type)) {
+            theType = InjectionUtils.getActualType(genericType);
+        } else {
+            theType = type;
+        }
+        XmlJavaTypeAdapter adapter = org.apache.cxf.jaxrs.utils.JAXBUtils.getAdapter(theType, anns);
+        theType = org.apache.cxf.jaxrs.utils.JAXBUtils.getTypeFromAdapter(adapter, theType, false);
+
+        return theType;
+    }
+
+    protected static Object checkAdapter(Object obj, Class<?> cls, Annotation[] anns, boolean marshal) {
+        XmlJavaTypeAdapter adapter = org.apache.cxf.jaxrs.utils.JAXBUtils.getAdapter(cls, anns);
+        return org.apache.cxf.jaxrs.utils.JAXBUtils.useAdapter(obj, adapter, marshal);
+    }
+
+    protected Schema getSchema() {
+        return getSchema(null);
+    }
+
+    protected Schema getSchema(Class<?> cls) {
+        // deal with the typical default case first
+        if (schema == null && schemaHandlers == null) {
+            return null;
+        }
+
+        if (schema != null) {
+            return schema;
+        }
+        SchemaHandler handler = schemaHandlers.get(cls.getName());
+        return handler != null ? handler.getSchema() : null;
+    }
+
+
+    public void clearContexts() {
+        classContexts.clear();
+        packageContexts.clear();
+    }
+
+    //TODO: move these methods into the dedicated utility class
+    protected static StringBuilder handleExceptionStart(Exception e) {
+        LOG.warning(ExceptionUtils.getStackTrace(e));
+        StringBuilder sb = new StringBuilder();
+        if (e.getMessage() != null) {
+            sb.append(e.getMessage()).append(". ");
+        }
+        if (e.getCause() != null && e.getCause().getMessage() != null) {
+            sb.append(e.getCause().getMessage()).append(". ");
+        }
+        return sb;
+    }
+
+    protected static void handleExceptionEnd(Throwable t, String message, boolean read) throws NoContentException {
+        if (t instanceof WstxEOFException && t.getMessage().startsWith("Unexpected EOF in prolog")){
+            String noContent = new org.apache.cxf.common.i18n.Message("EMPTY_BODY", BUNDLE).toString();
+            LOG.warning(noContent);
+            throw new NoContentException(noContent);
+        }
+        Response.Status status = read
+            ? Response.Status.BAD_REQUEST : Response.Status.INTERNAL_SERVER_ERROR;
+        Response r = JAXRSUtils.toResponseBuilder(status)
+            .type(MediaType.TEXT_PLAIN).entity(message).build();
+        throw read ? ExceptionUtils.toBadRequestException(t, r)
+            : ExceptionUtils.toInternalServerErrorException(t, r);
+    }
+
+    protected void handleJAXBException(JAXBException e, boolean read) throws NoContentException {
+        StringBuilder sb = handleExceptionStart(e);
+        Throwable linked = e.getLinkedException();
+        if (linked != null && linked.getMessage() != null) {
+            Throwable cause = linked;
+            while (read && cause != null) {
+                if (cause instanceof XMLStreamException && cause.getMessage().startsWith("Maximum Number")) {
+                    throw ExceptionUtils.toWebApplicationException(null, JAXRSUtils.toResponse(413));
+                }
+                if (cause instanceof DepthExceededStaxException) {
+                    throw ExceptionUtils.toWebApplicationException(null, JAXRSUtils.toResponse(413));
+                }
+                cause = cause.getCause();
+            }
+            String msg = linked.getMessage();
+            if (sb.lastIndexOf(msg) == -1) {
+                sb.append(msg).append(". ");
+            }
+        }
+        Throwable t = linked != null ? linked : e.getCause() != null ? e.getCause() : e;
+        String message = new org.apache.cxf.common.i18n.Message("JAXB_EXCEPTION",
+                             BUNDLE, sb.toString()).toString();
+        handleExceptionEnd(t, message, read);
+    }
+
+    protected void handleXMLStreamException(XMLStreamException e, boolean read) throws NoContentException {
+        StringBuilder sb = handleExceptionStart(e);
+        handleExceptionEnd(e, sb.toString(), read);
+    }
+
+    public void setOutTransformElements(Map<String, String> outElements) {
+        this.outElementsMap = outElements;
+    }
+
+    public void setInAppendElements(Map<String, String> inElements) {
+        this.inAppendMap = inElements;
+    }
+
+    public void setInTransformElements(Map<String, String> inElements) {
+        this.inElementsMap = inElements;
+    }
+
+    public void setOutAppendElements(Map<String, String> map) {
+        this.outAppendMap = map;
+    }
+
+    public void setOutDropElements(List<String> dropElementsSet) {
+        this.outDropElements = dropElementsSet;
+    }
+
+    public void setInDropElements(List<String> dropElementsSet) {
+        this.inDropElements = dropElementsSet;
+    }
+
+    public void setAttributesToElements(boolean value) {
+        this.attributesToElements = value;
+    }
+
+    public void setSkipJaxbChecks(boolean skipJaxbChecks) {
+        this.skipJaxbChecks = skipJaxbChecks;
+    }
+
+    public boolean isSkipJaxbChecks() {
+        return skipJaxbChecks;
+    }
+
+    protected XMLStreamWriter createTransformWriterIfNeeded(XMLStreamWriter writer,
+                                                            OutputStream os,
+                                                            boolean dropAtXmlLevel) {
+        return TransformUtils.createTransformWriterIfNeeded(writer, os,
+                                                      outElementsMap,
+                                                      dropAtXmlLevel ? outDropElements : null,
+                                                      outAppendMap,
+                                                      attributesToElements,
+                                                      null);
+    }
+
+    protected XMLStreamReader createTransformReaderIfNeeded(XMLStreamReader reader, InputStream is) {
+        return TransformUtils.createTransformReaderIfNeeded(reader, is,
+                                                            inDropElements,
+                                                            inElementsMap,
+                                                            inAppendMap,
+                                                            true);
+    }
+
+    protected XMLStreamReader createDepthReaderIfNeeded(XMLStreamReader reader, InputStream is) {
+        DocumentDepthProperties props = getDepthProperties();
+        if (props != null && props.isEffective()) {
+            reader = TransformUtils.createNewReaderIfNeeded(reader, is);
+            reader = new DepthRestrictingStreamReader(reader, props);
+        } else if (reader != null) {
+            reader = configureReaderRestrictions(reader);
+        }
+        return reader;
+    }
+
+    protected XMLStreamReader configureReaderRestrictions(XMLStreamReader reader) {
+        Message message = PhaseInterceptorChain.getCurrentMessage();
+        if (message != null) {
+            try {
+                return StaxUtils.configureReader(reader, message);
+            } catch (XMLStreamException ex) {
+                throw ExceptionUtils.toInternalServerErrorException(ex, null);
+            }
+        }
+        return reader;
+    }
+
+    protected DocumentDepthProperties getDepthProperties() {
+        return depthProperties;
+    }
+
+    public void setValidateBeforeWrite(boolean validateBeforeWrite) {
+        this.validateBeforeWrite = validateBeforeWrite;
+    }
+
+    public void setValidateOutput(boolean validateOutput) {
+        this.validateOutputIfPossible = validateOutput;
+    }
+    public void setValidateInput(boolean validateInput) {
+        this.validateInputIfPossible = validateInput;
+    }
+
+    public void setDepthProperties(DocumentDepthProperties depthProperties) {
+        this.depthProperties = depthProperties;
+    }
+
+    public void setUnmarshallerListener(Unmarshaller.Listener unmarshallerListener) {
+        this.unmarshallerListener = unmarshallerListener;
+    }
+
+    public void setMarshallerListener(Marshaller.Listener marshallerListener) {
+        this.marshallerListener = marshallerListener;
+    }
+
+    public void setNamespaceMapperPropertyName(String namespaceMapperProperty) {
+        this.namespaceMapperPropertyName = namespaceMapperProperty;
+    }
+
+    @XmlRootElement
+    protected static class CollectionWrapper {
+
+        @XmlAnyElement(lax = true)
+        private List<?> l;
+
+        public void setList(List<?> list) {
+            l = list;
+        }
+
+        public List<?> getList() {
+            if (l == null) {
+                l = new ArrayList<>();
+            }
+            return l;
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> Object getCollectionOrArray(Unmarshaller unm,
+                                               Class<T> type,
+                                               Class<?> collectionType,
+                                               Type genericType,
+                                               XmlJavaTypeAdapter adapter) throws JAXBException {
+            List<?> theList = getList();
+            boolean adapterChecked = false;
+            if (!theList.isEmpty()) {
+                Object first = theList.get(0);
+
+                if (first instanceof Element) {
+                    List<Object> newList = new ArrayList<>(theList.size());
+                    for (Object o : theList) {
+                        newList.add(unm.unmarshal((Element)o, type));
+                    }
+                    theList = newList;
+                }
+
+                first = theList.get(0);
+                Type[] types = InjectionUtils.getActualTypes(genericType);
+                boolean isJaxbElement = types != null && types.length > 0
+                    && InjectionUtils.getRawType(types[0]) == JAXBElement.class;
+
+                if (first instanceof JAXBElement && !isJaxbElement && !JAXBElement.class.isAssignableFrom(type)) {
+                    adapterChecked = true;
+                    List<Object> newList = new ArrayList<>(theList.size());
+                    for (Object o : theList) {
+                        newList.add(org.apache.cxf.jaxrs.utils.JAXBUtils.useAdapter(
+                                        ((JAXBElement<?>)o).getValue(), adapter, false));
+                    }
+                    theList = newList;
+                } else if (!(first instanceof JAXBElement) && isJaxbElement) {
+                    List<Object> newList = new ArrayList<>(theList.size());
+                    XmlRootElement root = type.getAnnotation(XmlRootElement.class);
+                    QName qname = getQNameFromNamespaceAndName(root.namespace(), root.name(), type, false);
+                    @SuppressWarnings("rawtypes")
+                    Class theType = type;
+                    for (Object o : theList) {
+                        newList.add(new JAXBElement<Object>(qname, theType, null, o));
+                    }
+                    theList = newList;
+                }
+            }
+            if (collectionType.isArray()) {
+                T[] values = (T[])Array.newInstance(type, theList.size());
+                for (int i = 0; i < theList.size(); i++) {
+                    values[i] = (T)org.apache.cxf.jaxrs.utils.JAXBUtils.useAdapter(
+                                       theList.get(i), adapter, false);
+                }
+                return values;
+            }
+            if (!adapterChecked && adapter != null) {
+                List<Object> newList = new ArrayList<>(theList.size());
+                for (Object o : theList) {
+                    newList.add(org.apache.cxf.jaxrs.utils.JAXBUtils.useAdapter(o, adapter, false));
+                }
+                theList = newList;
+            }
+            if (collectionType == Set.class) {
+                return new HashSet<>(theList);
+            }
+            return theList;
+        }
+
+    }
+
+    protected static class JAXBCollectionWrapperReader extends DepthXMLStreamReader {
+
+        private boolean firstName;
+        private boolean firstNs;
+
+        public JAXBCollectionWrapperReader(XMLStreamReader reader) {
+            super(reader);
+        }
+
+        @Override
+        public String getNamespaceURI() {
+            if (!firstNs) {
+                firstNs = true;
+                return "";
+            }
+            return super.getNamespaceURI();
+        }
+
+        @Override
+        public String getLocalName() {
+            if (!firstName) {
+                firstName = true;
+                return "collectionWrapper";
+            }
+
+            return super.getLocalName();
+        }
+
+    }
+
+
+}