You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2015/08/03 19:11:44 UTC

tomee git commit: CXF 3.1.2

Repository: tomee
Updated Branches:
  refs/heads/master 9beea6937 -> 3ea255664


CXF 3.1.2


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/3ea25566
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/3ea25566
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/3ea25566

Branch: refs/heads/master
Commit: 3ea25566488eac63873b9ce6380991fb391cef8e
Parents: 9beea69
Author: Romain Manni-Bucau <rm...@apache.org>
Authored: Mon Aug 3 19:11:35 2015 +0200
Committer: Romain Manni-Bucau <rm...@apache.org>
Committed: Mon Aug 3 19:11:35 2015 +0200

----------------------------------------------------------------------
 pom.xml                                         |   2 +-
 .../apache/openejb/server/cxf/rs/CxfHacks.java  |   1 +
 .../openejb/server/cxf/rs/CxfRSService.java     |  60 +----
 .../server/cxf/rs/CxfRsHttpListener.java        | 246 ++++++++++++-------
 .../server/cxf/rs/CustomProviderTest.java       |  32 ++-
 .../cxf/rs/CustomProviderWithConfigTest.java    |  14 +-
 .../cxf/rs/DiscoverCustomProviderTest.java      |  17 +-
 .../cxf/rs/ProviderWithConstructorTest.java     |   4 +-
 .../openejb/server/cxf/rs/SortProviderTest.java |  54 ++--
 9 files changed, 254 insertions(+), 176 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index b8a1e8c..c83caa9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -128,7 +128,7 @@
 
     <tomcat.version>8.0.24</tomcat.version>
 
-    <cxf.version>3.1.0</cxf.version>
+    <cxf.version>3.1.2</cxf.version>
     <ehcache.version>2.8.5</ehcache.version>
     <!-- used by cxf for security (replay attack) -->
     <jetty.version>7.5.3.v20111011</jetty.version>

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfHacks.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfHacks.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfHacks.java
index f83997b..0780e84 100644
--- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfHacks.java
+++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfHacks.java
@@ -18,6 +18,7 @@ package org.apache.openejb.server.cxf.rs;
 
 import org.apache.cxf.common.util.ClassHelper;
 import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.server.cxf.transport.util.CxfUtil;
 import org.apache.openejb.util.reflection.Reflections;
 
 public final class CxfHacks {

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
index 581508a..61f016c 100644
--- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
+++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRSService.java
@@ -19,15 +19,6 @@ package org.apache.openejb.server.cxf.rs;
 import org.apache.cxf.Bus;
 import org.apache.cxf.binding.BindingFactoryManager;
 import org.apache.cxf.jaxrs.JAXRSBindingFactory;
-import org.apache.cxf.jaxrs.client.ClientProviderFactory;
-import org.apache.cxf.jaxrs.provider.BinaryDataProvider;
-import org.apache.cxf.jaxrs.provider.DataSourceProvider;
-import org.apache.cxf.jaxrs.provider.FormEncodingProvider;
-import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
-import org.apache.cxf.jaxrs.provider.MultipartProvider;
-import org.apache.cxf.jaxrs.provider.PrimitiveTextProvider;
-import org.apache.cxf.jaxrs.provider.ProviderFactory;
-import org.apache.cxf.jaxrs.provider.SourceProvider;
 import org.apache.cxf.transport.DestinationFactory;
 import org.apache.cxf.transport.http.HTTPTransportFactory;
 import org.apache.johnzon.jaxrs.JohnzonProvider;
@@ -52,7 +43,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -60,9 +50,9 @@ import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.net.Socket;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import javax.enterprise.context.ApplicationScoped;
@@ -190,7 +180,7 @@ public class CxfRSService extends RESTService {
                 }
             }
             hacksOn();
-            initCxfClientBuilderProviders(bus);
+            initCxfProviders(bus);
         } finally {
             if (oldLoader != null) {
                 CxfUtil.clearBusLoader(oldLoader);
@@ -198,33 +188,20 @@ public class CxfRSService extends RESTService {
         }
     }
 
-    private void initCxfClientBuilderProviders(final Bus bus) {
-        if (bus.getProperty("jaxrs.shared.client.factory") == null) {
-            try {
-                final Constructor<ClientProviderFactory> constructor = ClientProviderFactory.class.getDeclaredConstructor(ProviderFactory.class, Bus.class);
-                constructor.setAccessible(true);
-                final ClientProviderFactory factory = constructor.newInstance(null, bus);
-
-                final Method set = ClientProviderFactory.class.getDeclaredMethod("setProviders", Object[].class);
-                set.setAccessible(true);
+    private void initCxfProviders(final Bus bus) {
+        if (bus.getProperty("org.apache.cxf.jaxrs.bus.providers") == null) {
+            bus.setProperty("skip.default.json.provider.registration", "true"); // client jaxrs, we want johnzon not jettison
 
+            try {
+                final List<Object> all;
                 final String userProviders = SystemInstance.get().getProperty("openejb.jaxrs.client.providers");
-                final Object[][] providers;  // vararg -> array, reflection -> array
                 if (userProviders == null) {
-                    providers = new Object[][] {{
-                            new BinaryDataProvider<>(),
-                            new SourceProvider<>(),
-                            new DataSourceProvider<>(),
-                            new FormEncodingProvider<>(),
-                            new PrimitiveTextProvider<>(),
+                    (all = new ArrayList<>(2)).addAll(asList(
                             new JohnzonProvider<>(),
-                            new JAXBElementProvider<>(),
-                            new JsrProvider(),
-                            new MultipartProvider()
-                    }};
+                            new JsrProvider()
+                    ));
                 } else {
-                    final Collection<Object> all = new ArrayList<>(16);
-
+                    all = new ArrayList<>(4 /* blind guess */);
                     for (String p : userProviders.split(" *, *")) {
                         p= p.trim();
                         if (p.isEmpty()) {
@@ -235,21 +212,10 @@ public class CxfRSService extends RESTService {
                     }
 
                     all.addAll(asList( // added after to be after in the list once sorted
-                            new BinaryDataProvider<>(),
-                            new SourceProvider<>(),
-                            new DataSourceProvider<>(),
-                            new FormEncodingProvider<>(),
-                            new PrimitiveTextProvider<>(),
                             new JohnzonProvider<>(),
-                            new JAXBElementProvider<>(),
-                            new JsrProvider(),
-                            new MultipartProvider()));
-
-                    providers = new Object[][] { all.toArray(new Object[all.size()]) };
+                            new JsrProvider()));
                 }
-                set.invoke(factory, providers);
-
-                bus.setProperty("jaxrs.shared.client.factory", factory);
+                bus.setProperty("org.apache.cxf.jaxrs.bus.providers", all);
             } catch (final Exception e) {
                 throw new IllegalStateException(e);
             }

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
index fe5e613..e3eaae4 100644
--- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
+++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
@@ -27,25 +27,20 @@ import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
 import org.apache.cxf.jaxrs.JAXRSServiceImpl;
 import org.apache.cxf.jaxrs.ext.ResourceComparator;
-import org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper;
 import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
 import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
 import org.apache.cxf.jaxrs.model.ClassResourceInfo;
 import org.apache.cxf.jaxrs.model.MethodDispatcher;
 import org.apache.cxf.jaxrs.model.OperationResourceInfo;
-import org.apache.cxf.jaxrs.provider.BinaryDataProvider;
-import org.apache.cxf.jaxrs.provider.DataSourceProvider;
-import org.apache.cxf.jaxrs.provider.FormEncodingProvider;
-import org.apache.cxf.jaxrs.provider.JAXBElementProvider;
-import org.apache.cxf.jaxrs.provider.MultipartProvider;
-import org.apache.cxf.jaxrs.provider.PrimitiveTextProvider;
-import org.apache.cxf.jaxrs.provider.SourceProvider;
+import org.apache.cxf.jaxrs.model.ProviderInfo;
+import org.apache.cxf.jaxrs.provider.ProviderFactory;
+import org.apache.cxf.jaxrs.provider.ServerProviderFactory;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.jaxrs.validation.ValidationExceptionMapper;
+import org.apache.cxf.message.Message;
 import org.apache.cxf.service.invoker.Invoker;
 import org.apache.cxf.transport.DestinationFactory;
 import org.apache.cxf.transport.servlet.BaseUrlHelper;
-import org.apache.johnzon.jaxrs.JohnzonProvider;
-import org.apache.johnzon.jaxrs.JsrProvider;
 import org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter;
 import org.apache.openejb.AppContext;
 import org.apache.openejb.BeanContext;
@@ -81,28 +76,18 @@ import org.apache.openejb.util.AppFinder;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
 import org.apache.openejb.util.proxy.ProxyEJB;
+import org.apache.openejb.util.reflection.Reflections;
 import org.apache.webbeans.config.WebBeansContext;
 import org.apache.webbeans.container.BeanManagerImpl;
 import org.apache.webbeans.context.creational.CreationalContextImpl;
 
-import javax.enterprise.context.spi.CreationalContext;
-import javax.enterprise.inject.spi.Bean;
-import javax.management.ObjectName;
-import javax.management.openmbean.TabularData;
-import javax.naming.Context;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.ws.rs.ConstrainedTo;
-import javax.ws.rs.RuntimeType;
-import javax.ws.rs.core.Application;
-import javax.xml.bind.Marshaller;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.util.ArrayList;
@@ -119,6 +104,22 @@ import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.logging.Level;
 import java.util.regex.Pattern;
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.management.ObjectName;
+import javax.management.openmbean.TabularData;
+import javax.naming.Context;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.ConstrainedTo;
+import javax.ws.rs.RuntimeType;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
 
 import static org.apache.openejb.loader.JarLocation.jarLocation;
 
@@ -230,7 +231,7 @@ public class CxfRsHttpListener implements RsHttpListener {
         }
 
         String path = request.getRequestURI().substring(request.getContextPath().length());
-        if (path == null || path.isEmpty()) {
+        if (path.isEmpty()) {
             path = "/";
         }
         for (final Pattern pattern : staticResourcesList) {
@@ -461,20 +462,9 @@ public class CxfRsHttpListener implements RsHttpListener {
     }
 
     private static void addMandatoryProviders(final Collection<Object> instances) {
-        instances.add(new JsrProvider());
         instances.add(new WadlDocumentMessageBodyWriter());
         instances.add(EJBAccessExceptionMapper.INSTANCE);
         instances.add(new ValidationExceptionMapper());
-
-        if ("true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.jaxrs.cxf.add-cxf-providers", "false"))) {
-            instances.add(new WebApplicationExceptionMapper());
-            instances.add(new BinaryDataProvider<>());
-            instances.add(new SourceProvider<>());
-            instances.add(new DataSourceProvider<>());
-            instances.add(new FormEncodingProvider<>());
-            instances.add(new PrimitiveTextProvider<>());
-            instances.add(new MultipartProvider());
-        }
     }
 
     private Object newProvider(final Class<?> clazz) throws IllegalAccessException, InstantiationException {
@@ -590,6 +580,20 @@ public class CxfRsHttpListener implements RsHttpListener {
             try {
                 server = factory.create();
                 fireServerCreated(oldLoader);
+
+                final ServerProviderFactory spf = ServerProviderFactory.class.cast(server.getEndpoint().get(ServerProviderFactory.class.getName()));
+                LOGGER.info("Using readers:");
+                for (final Object provider : List.class.cast(Reflections.get(spf, "messageReaders"))) {
+                    LOGGER.info("     " + ProviderInfo.class.cast(provider).getProvider());
+                }
+                LOGGER.info("Using writers:");
+                for (final Object provider : List.class.cast(Reflections.get(spf, "messageWriters"))) {
+                    LOGGER.info("     " + ProviderInfo.class.cast(provider).getProvider());
+                }
+                LOGGER.info("Using exception mappers:");
+                for (final Object provider : List.class.cast(Reflections.get(spf, "exceptionMappers"))) {
+                    LOGGER.info("     " + ProviderInfo.class.cast(provider).getProvider());
+                }
             } finally {
                 try {
                     SERVER_IMPL_LOGGER.setLevel(level);
@@ -778,6 +782,12 @@ public class CxfRsHttpListener implements RsHttpListener {
                                   final ServiceConfiguration serviceConfiguration,
                                   final JAXRSServerFactoryBean factory,
                                   final WebBeansContext ctx) {
+        if (!"true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.cxf.rs.skip-provider-sorting", "false"))) {
+            final Comparator<?> providerComparator = findProviderComparator(serviceConfiguration, ctx);
+            if (providerComparator != null) {
+                factory.setProviderComparator(providerComparator);
+            }
+        }
         CxfUtil.configureEndpoint(factory, serviceConfiguration, CXF_JAXRS_PREFIX);
 
         final Collection<ServiceInfo> services = serviceConfiguration.getAvailableServices();
@@ -845,15 +855,13 @@ public class CxfRsHttpListener implements RsHttpListener {
         if (providersConfig != null) {
             providers = ServiceInfos.resolve(services, providersConfig.toArray(new String[providersConfig.size()]), OpenEJBProviderFactory.INSTANCE);
             if (providers != null && additionalProviders != null && !additionalProviders.isEmpty()) {
-                providers.addAll(sortProviders(serviceConfiguration, ctx, additionalProviders));
+                providers.addAll(providers(serviceConfiguration.getAvailableServices(), additionalProviders, ctx));
             }
         }
         if (providers == null) {
             providers = new ArrayList<>(4);
             if (additionalProviders != null && !additionalProviders.isEmpty()) {
-                providers.addAll(sortProviders(serviceConfiguration, ctx, additionalProviders));
-            } else {
-                providers.addAll(defaultProviders());
+                providers.addAll(providers(serviceConfiguration.getAvailableServices(), additionalProviders, ctx));
             }
         }
 
@@ -864,28 +872,19 @@ public class CxfRsHttpListener implements RsHttpListener {
         SystemInstance.get().fireEvent(new ExtensionProviderRegistration(
                 AppFinder.findAppContextOrWeb(Thread.currentThread().getContextClassLoader(), AppFinder.AppContextTransformer.INSTANCE), providers));
 
-        LOGGER.info("Using providers:");
-        for (final Object provider : providers) {
-            LOGGER.info("     " + provider);
+        if (!providers.isEmpty()) {
+            factory.setProviders(providers);
         }
-        factory.setProviders(providers);
     }
 
-    private List<Object> sortProviders(final ServiceConfiguration serviceConfiguration, final WebBeansContext ctx,
-                                       final Collection<Object> additionalProviders) {
-        final Collection<ServiceInfo> services = serviceConfiguration.getAvailableServices();
-        final List<Object> loadedProviders = providers(services, additionalProviders, ctx);
-        if ("true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.cxf.rs.skip-provider-sorting", "false"))) {
-            return loadedProviders;
-        }
-
+    private Comparator<?> findProviderComparator(final ServiceConfiguration serviceConfiguration, final WebBeansContext ctx) {
         final String comparatorKey = CXF_JAXRS_PREFIX + "provider-comparator";
         final String comparatorClass = serviceConfiguration.getProperties()
                                            .getProperty(comparatorKey, SystemInstance.get().getProperty(comparatorKey));
 
         Comparator<Object> comparator = null;
         if (comparatorClass == null) {
-            comparator = DefaultProviderComparator.INSTANCE;
+            return null; // try to rely on CXF behavior otherwise just reactivate DefaultProviderComparator.INSTANCE if it is an issue
         } else {
             final BeanManagerImpl bm = ctx == null ? null : ctx.getBeanManagerImpl();
             if (bm != null && bm.isInUse()) {
@@ -904,7 +903,7 @@ public class CxfRsHttpListener implements RsHttpListener {
             }
 
             if (comparator == null) {
-                comparator = Comparator.class.cast(ServiceInfos.resolve(services, comparatorClass));
+                comparator = Comparator.class.cast(ServiceInfos.resolve(serviceConfiguration.getAvailableServices(), comparatorClass));
             }
             if (comparator == null) {
                 try {
@@ -913,30 +912,38 @@ public class CxfRsHttpListener implements RsHttpListener {
                     throw new IllegalArgumentException(e);
                 }
             }
-        }
-        Collections.sort(loadedProviders, comparator);
-        return loadedProviders;
-    }
 
-    private static List<Object> defaultProviders() {
-        final JAXBElementProvider jaxb = new JAXBElementProvider();
-        final Map<String, Object> jaxbProperties = new HashMap<>();
-        jaxbProperties.put(Marshaller.JAXB_FRAGMENT, true);
-        jaxb.setMarshallerProperties(jaxbProperties);
+            for (final Type itf : comparator.getClass().getGenericInterfaces()) {
+                if (!ParameterizedType.class.isInstance(itf)) {
+                    continue;
+                }
 
-        final List<Object> providers = new ArrayList<>(2);
-        providers.add(new JohnzonProvider<>());
-        providers.add(jaxb);
-        return providers;
+                final ParameterizedType pt = ParameterizedType.class.cast(itf);
+                if (Comparator.class == pt.getRawType() && pt.getActualTypeArguments().length > 0) {
+                    final Type t = pt.getActualTypeArguments()[0];
+                    if (Class.class.isInstance(t) && ProviderInfo.class == t) {
+                        return comparator;
+                    }
+                    if (ParameterizedType.class.isInstance(t) && ProviderInfo.class == ParameterizedType.class.cast(t).getRawType()) {
+                        return comparator;
+                    }
+                }
+            }
+
+            return new ProviderComparatorWrapper(comparator);
+        }
     }
 
-    // we use Object cause an app with a custom comparator can desire to compare instances
-    private static final class DefaultProviderComparator implements Comparator<Object> {
-        private static final DefaultProviderComparator INSTANCE = new DefaultProviderComparator();
+    // public to ensure it can be configured since not setup by default anymore
+    public static final class DefaultProviderComparator extends ProviderFactory implements Comparator<ProviderInfo<?>> {
         private static final ClassLoader SYSTEM_LOADER = ClassLoader.getSystemClassLoader();
 
+        public DefaultProviderComparator() {
+            super(null);
+        }
+
         @Override
-        public int compare(final Object o1, final Object o2) {
+        public int compare(final ProviderInfo<?> o1, final ProviderInfo<?> o2) {
             if (o1 == o2 || (o1 != null && o1.equals(o2))) {
                 return 0;
             }
@@ -947,8 +954,17 @@ public class CxfRsHttpListener implements RsHttpListener {
                 return 1;
             }
 
-            final Class<?> c1 = o1.getClass();
-            final Class<?> c2 = o2.getClass();
+            final Class<?> c1 = o1.getProvider().getClass();
+            final Class<?> c2 = o2.getProvider().getClass();
+            if (c1.getName().startsWith("org.apache.cxf.")) {
+                if (!c2.getName().startsWith("org.apache.cxf.")) {
+                    return 1;
+                }
+                return -1;
+            }
+            if (c2.getName().startsWith("org.apache.cxf.")) {
+                return -1;
+            }
 
             final ClassLoader classLoader1 = c1.getClassLoader();
             final ClassLoader classLoader2 = c2.getClassLoader();
@@ -965,22 +981,64 @@ public class CxfRsHttpListener implements RsHttpListener {
                     return -1;
                 }
             } else {
-                final File l1 = jarLocation(c1);
-                final File l2 = jarLocation(c2);
-                if (l1 == null) {
-                    return 1;
+                int result = compareClasses(o1.getProvider(), o2.getProvider());
+                if (result != 0) {
+                    return result;
                 }
-                if (l2 == null) {
-                    return -1;
+
+                if (MessageBodyWriter.class.isInstance(o1.getProvider())) {
+                    final List<MediaType> types1 =
+                            JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o1.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
+                    final List<MediaType> types2 =
+                            JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o2.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM);
+
+                    if (types1.contains(MediaType.WILDCARD_TYPE) && !types2.contains(MediaType.WILDCARD_TYPE)) {
+                        return 1;
+                    }
+                    if (types2.contains(MediaType.WILDCARD_TYPE) && !types1.contains(MediaType.WILDCARD_TYPE)) {
+                        return -1;
+                    }
+
+                    result = JAXRSUtils.compareSortedMediaTypes(types1, types2, JAXRSUtils.MEDIA_TYPE_QS_PARAM);
+                    if (result != 0) {
+                        return result;
+                    }
+                }
+                if (MessageBodyReader.class.isInstance(o1.getProvider())) {
+                    final List<MediaType> types1 =
+                            JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o1.getProvider())), null);
+                    final List<MediaType> types2 =
+                            JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o2.getProvider())), null);
+
+                    result = JAXRSUtils.compareSortedMediaTypes(types1, types2, JAXRSUtils.MEDIA_TYPE_QS_PARAM);
+                    if (result != 0) {
+                        return result;
+                    }
                 }
 
-                try { // WEB-INF/classes will be before WEB-INF/lib automatically
-                    return l1.getCanonicalPath().compareTo(l2.getCanonicalPath());
-                } catch (final IOException e) {
+                final Boolean custom1 = o1.isCustom();
+                final Boolean custom2 = o2.isCustom();
+                final int customComp = custom1.compareTo(custom2) * -1;
+                if (customComp != 0) {
+                    return customComp;
+                }
+
+                try { // WEB-INF/classes will be before WEB-INF/lib
+                    final File file1 = jarLocation(c1);
+                    final File file2 = jarLocation(c2);
+                    if ("classes".equals(file1.getName())) {
+                        if ("classes".equals(file2.getName())) {
+                            return c1.getName().compareTo(c2.getName());
+                        }
+                        return -1;
+                    }
+                    if ("classes".equals(file2.getName())) {
+                        return 1;
+                    }
+                } catch (final Exception e) {
                     // no-op: sort by class name
                 }
             }
-
             return c1.getName().compareTo(c2.getName());
         }
 
@@ -994,6 +1052,30 @@ public class CxfRsHttpListener implements RsHttpListener {
             }
             return false;
         }
+
+        @Override
+        public Configuration getConfiguration(final Message message) {
+            throw new UnsupportedOperationException("not a real inheritance");
+        }
+
+        @Override
+        protected void setProviders(final boolean custom, final Object... providers) {
+            throw new UnsupportedOperationException("not a real inheritance");
+        }
+    }
+
+    // we use Object cause an app with a custom comparator can desire to compare instances
+    private static final class ProviderComparatorWrapper implements Comparator<ProviderInfo<?>> {
+        private final Comparator<Object> delegate;
+
+        private ProviderComparatorWrapper(final Comparator<Object> delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public int compare(final ProviderInfo<?> o1, final ProviderInfo<?> o2) {
+            return delegate.compare(o1.getProvider(), o2.getProvider());
+        }
     }
 
     private static class OpenEJBProviderFactory implements ServiceInfos.Factory {

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderTest.java
index 1b082ef..57deee1 100644
--- a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderTest.java
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderTest.java
@@ -26,6 +26,11 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Properties;
 import javax.ejb.Singleton;
 import javax.ejb.embeddable.EJBContainer;
 import javax.ws.rs.GET;
@@ -35,11 +40,6 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Properties;
 
 import static org.junit.Assert.assertEquals;
 
@@ -86,8 +86,8 @@ public class CustomProviderTest {
         @GET
         @Path("/reverse")
         @Produces("openejb/reverse")
-        public String go() {
-            return "redivorp";
+        public Message go() {
+            return new Message("redivorp");
         }
     }
 
@@ -97,8 +97,8 @@ public class CustomProviderTest {
         @GET
         @Path("/constant")
         @Produces("openejb/constant")
-        public String go() {
-            return "will be overriden";
+        public Message go() {
+            return new Message("will be overriden");
         }
     }
 
@@ -124,12 +124,12 @@ public class CustomProviderTest {
 
         @Override
         public boolean isWriteable(Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
-            return true;
+            return Message.class == rawType;
         }
 
         @Override
         public void writeTo(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
-            entityStream.write(reverse((String) t).getBytes());
+            entityStream.write(reverse(Message.class.cast(t).text).getBytes());
         }
     }
 
@@ -143,7 +143,7 @@ public class CustomProviderTest {
 
         @Override
         public boolean isWriteable(Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
-            return true;
+            return Message.class == rawType;
         }
 
         @Override
@@ -151,4 +151,12 @@ public class CustomProviderTest {
             entityStream.write("it works!".getBytes());
         }
     }
+
+    public static class Message {
+        private final String text;
+
+        public Message(final String text) {
+            this.text = text;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderWithConfigTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderWithConfigTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderWithConfigTest.java
index e1806f6..c7799de 100644
--- a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderWithConfigTest.java
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/CustomProviderWithConfigTest.java
@@ -25,6 +25,11 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Properties;
 import javax.ejb.Singleton;
 import javax.ejb.embeddable.EJBContainer;
 import javax.ws.rs.GET;
@@ -34,11 +39,6 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Properties;
 
 import static org.junit.Assert.assertEquals;
 
@@ -77,8 +77,8 @@ public class CustomProviderWithConfigTest {
     public static class CustomizedService {
         @GET
         @Produces("openejb/conf")
-        public String go() {
-            return "";
+        public CustomizedService go() {
+            return new CustomizedService();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java
index a2a7697..b0b29a5 100644
--- a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java
@@ -26,6 +26,12 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
 import javax.ejb.Singleton;
 import javax.ejb.embeddable.EJBContainer;
 import javax.ws.rs.GET;
@@ -35,11 +41,6 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.util.Properties;
 
 import static org.junit.Assert.assertEquals;
 
@@ -80,8 +81,8 @@ public class DiscoverCustomProviderTest {
         @GET
         @Path("service")
         @Produces("discover/reverse")
-        public String go() {
-            return "skcor ti";
+        public AtomicReference<String> go() {
+            return new AtomicReference<>("skcor ti");
         }
     }
 
@@ -107,7 +108,7 @@ public class DiscoverCustomProviderTest {
 
         @Override
         public void writeTo(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
-            entityStream.write(reverse((String) t).getBytes());
+            entityStream.write(reverse(AtomicReference.class.cast(t).get().toString()).getBytes());
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithConstructorTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithConstructorTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithConstructorTest.java
index 1b1ce04..988e8da 100644
--- a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithConstructorTest.java
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/ProviderWithConstructorTest.java
@@ -87,8 +87,8 @@ public class ProviderWithConstructorTest {
     public static class AnEndpointToCheckAProvider {
         @GET
         @Produces("openejb/constructor")
-        public String bar() {
-            return "bar"; // whatever the value is the provider will return the context path
+        public AnEndpointToCheckAProvider bar() {
+            return new AnEndpointToCheckAProvider();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/3ea25566/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SortProviderTest.java
----------------------------------------------------------------------
diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SortProviderTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SortProviderTest.java
index 74e5f38..0b10dae 100644
--- a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SortProviderTest.java
+++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SortProviderTest.java
@@ -25,9 +25,18 @@ import org.apache.openejb.testing.Configuration;
 import org.apache.openejb.testing.Module;
 import org.apache.openejb.testng.PropertiesBuilder;
 import org.apache.openejb.util.NetworkUtil;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.util.Comparator;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -37,17 +46,11 @@ import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 import javax.ws.rs.ext.Providers;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.net.URL;
-import java.util.Comparator;
-import java.util.Properties;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+@Ignore("no more supported by CXF - chaining providers")
 public class SortProviderTest {
     @Rule
     public final ApplicationComposerRule container = new ApplicationComposerRule(this);
@@ -81,7 +84,24 @@ public class SortProviderTest {
         @Override
         public int compare(final Object o1, final Object o2) {
             saw = true;
-            return o1.getClass().getName().compareTo(o2.getClass().getName());
+
+            final Class<?> c1 = o1.getClass();
+            if (c1 == ATestProvider11.class) {
+                return -1;
+            }
+
+            final Class<?> c2 = o2.getClass();
+            if (c2 == ATestProvider11.class) {
+                return 1;
+            }
+            if (c1 == ATestProviderA.class) {
+                return -1;
+            }
+            if (c2 == ATestProviderA.class) {
+                return 1;
+            }
+
+            return c1.getName().compareTo(c2.getName());
         }
     }
 
@@ -92,14 +112,14 @@ public class SortProviderTest {
 
         @GET
         @Produces("test/test")
-        public String asserts() {
-            return "fail";
+        public AtomicReference<String> asserts() {
+            return new AtomicReference<>("fail");
         }
     }
 
     @Provider
     @Produces("test/test")
-    public static class TestProviderA<T> implements MessageBodyWriter<T> {
+    public static class ATestProviderA implements MessageBodyWriter<AtomicReference<String>> {
         private String reverse(String str) {
             if (str == null) {
                 return "";
@@ -113,7 +133,7 @@ public class SortProviderTest {
         }
 
         @Override
-        public long getSize(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        public long getSize(AtomicReference<String> t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return -1;
         }
 
@@ -123,16 +143,16 @@ public class SortProviderTest {
         }
 
         @Override
-        public void writeTo(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
-            entityStream.write(reverse((String) t).getBytes());
+        public void writeTo(AtomicReference<String> t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
+            entityStream.write(reverse(t.get()).getBytes());
         }
     }
 
     @Provider
     @Produces("test/test")
-    public static class TestProvider11<T> implements MessageBodyWriter<T> {
+    public static class ATestProvider11 implements MessageBodyWriter<AtomicReference<?>> {
         @Override
-        public long getSize(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        public long getSize(AtomicReference<?> t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
             return -1;
         }
 
@@ -142,7 +162,7 @@ public class SortProviderTest {
         }
 
         @Override
-        public void writeTo(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
+        public void writeTo(AtomicReference<?> t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
             entityStream.write("it works!".getBytes());
         }
     }