You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by el...@apache.org on 2009/09/23 15:18:42 UTC

svn commit: r818093 - in /incubator/wink/trunk: wink-common/src/main/java/org/apache/wink/common/internal/registry/ wink-common/src/main/java/org/apache/wink/common/internal/utils/ wink-common/src/test/java/org/apache/wink/common/internal/providers/ wi...

Author: elman
Date: Wed Sep 23 13:18:42 2009
New Revision: 818093

URL: http://svn.apache.org/viewvc?rev=818093&view=rev
Log:
Added support of declared generic type on providers.
See [WINK-193]

Added:
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MyPrioritizedProvider.java   (with props)
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MySecondaryProvider.java   (with props)
Modified:
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/GenericsUtils.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/ProvidersContextResolverTest.java
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/entity/ProvidersMessageBodyTest.java
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/ProvidersRegistry11Test.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/MessageBodyWriterProviderCorrectParametersTest.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/ProvidersParametersOnErrorPathTest.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/UserProvidersOverBuiltinProviderTest.java

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/ProvidersRegistry.java Wed Sep 23 13:18:42 2009
@@ -26,10 +26,11 @@
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -57,6 +58,7 @@
 import org.apache.wink.common.internal.lifecycle.ObjectFactory;
 import org.apache.wink.common.internal.utils.AnnotationUtils;
 import org.apache.wink.common.internal.utils.GenericsUtils;
+import org.apache.wink.common.internal.utils.MediaTypeUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -428,7 +430,9 @@
     private abstract class MediaTypeMap<T> {
 
         private final Map<MediaType, Set<ObjectFactory<T>>>                                          data           =
-                                                                                                                        new LinkedHashMap<MediaType, Set<ObjectFactory<T>>>();
+                                                                                                                        new HashMap<MediaType, Set<ObjectFactory<T>>>();
+        private boolean                                                                              dataSorted     =
+                                                                                                                        false;
         private final Class<?>                                                                       rawType;
 
         private final Map<Class<?>, SoftReference<ConcurrentMap<MediaType, List<ObjectFactory<T>>>>> providersCache =
@@ -471,91 +475,57 @@
             List<ObjectFactory<T>> list = mediaTypeToProvidersCache.get(mediaType);
 
             if (list == null) {
-                if (subtype.equals(MediaType.MEDIA_TYPE_WILDCARD) || type
-                    .equals(MediaType.MEDIA_TYPE_WILDCARD)) {
-                    list = getProvidersByWildcardMediaType(mediaType, cls);
-                    mediaTypeToProvidersCache.put(mediaType, list);
-                    return list;
-                }
-                list = new ArrayList<ObjectFactory<T>>();
-                if (!mediaType.getParameters().isEmpty()) {
-                    mediaType = new MediaType(type, subtype);
-                }
-                Set<ObjectFactory<T>> set = data.get(mediaType);
-                limitByType(list, set, cls);
-                set = data.get(new MediaType(type, MediaType.MEDIA_TYPE_WILDCARD));
-                limitByType(list, set, cls);
-                set = data.get(MediaType.WILDCARD_TYPE);
-                limitByType(list, set, cls);
-
+                list = internalGetProvidersByMediaType(mediaType, cls);
                 mediaTypeToProvidersCache.put(mediaType, list);
             }
 
             return list;
         }
 
-        private List<ObjectFactory<T>> getProvidersByWildcardMediaType(MediaType mediaType,
+        private List<ObjectFactory<T>> internalGetProvidersByMediaType(MediaType mediaType,
                                                                        Class<?> cls) {
 
-            // according to JSR311 3.8, the providers must be searched
-            // using a concrete type
-            // if the providers are searched using a wildcard, it means
-            // that the call is done
-            // from the Providers interface, therefore isCompatible method
-            // should be used
-            // the search here is less efficient that the regular search
-            // see https://issues.apache.org/jira/browse/WINK-47
-
-            List<ObjectFactory<T>> list = new ArrayList<ObjectFactory<T>>();
-
-            ArrayList<Entry<MediaType, Set<ObjectFactory<T>>>> compatibleList =
-                new ArrayList<Entry<MediaType, Set<ObjectFactory<T>>>>();
-            for (Entry<MediaType, Set<ObjectFactory<T>>> entry : data.entrySet()) {
-                if (entry.getKey().isCompatible(mediaType)) {
-                    compatibleList.add(entry);
-                }
-            }
-
-            // sorts according to the following algorithm: n / m > n / * > * / *
-            // in descending order
-            // see https://issues.apache.org/jira/browse/WINK-82
-            Collections.sort(compatibleList, Collections
-                .reverseOrder(new Comparator<Entry<MediaType, Set<ObjectFactory<T>>>>() {
-
-                    public int compare(Entry<MediaType, Set<ObjectFactory<T>>> o1,
-                                       Entry<MediaType, Set<ObjectFactory<T>>> o2) {
-                        MediaType m1 = o1.getKey();
-                        MediaType m2 = o2.getKey();
-                        int compareTypes = compareTypes(m1.getType(), m2.getType());
-                        if (compareTypes == 0) {
-                            return compareTypes(m1.getSubtype(), m2.getSubtype());
+            @SuppressWarnings("unchecked")
+            Entry<MediaType, Set<ObjectFactory<T>>>[] entrySet =
+                data.entrySet().toArray(new Entry[0]);
+
+            if (!dataSorted) {
+                // It's important to sort the media types here to ensure that
+                // provider of the more dominant media type will precede, when
+                // adding to the compatible set.
+                Arrays.sort(entrySet, Collections
+                    .reverseOrder(new Comparator<Entry<MediaType, Set<ObjectFactory<T>>>>() {
+
+                        public int compare(Entry<MediaType, Set<ObjectFactory<T>>> o1,
+                                           Entry<MediaType, Set<ObjectFactory<T>>> o2) {
+                            return MediaTypeUtils.compareTo(o1.getKey(), o2.getKey());
                         }
-                        return compareTypes;
-                    }
+                    }));
+                dataSorted = true;
+            }
 
-                    private int compareTypes(String type1, String type2) {
-                        if (type1.equals(MediaType.MEDIA_TYPE_WILDCARD)) {
-                            if (type2.equals(MediaType.MEDIA_TYPE_WILDCARD)) {
-                                // both types are wildcards
-                                return 0;
-                            }
-                            // only type2 is concrete
-                            // type2 > type1
-                            return -1;
-                        }
-                        if (type2.equals(MediaType.MEDIA_TYPE_WILDCARD)) {
-                            // only type1 is concrete
-                            return 1;
+            Set<ObjectFactory<T>> compatible =
+                new TreeSet<ObjectFactory<T>>(Collections.reverseOrder());
+            for (Entry<MediaType, Set<ObjectFactory<T>>> entry : entrySet) {
+                if (entry.getKey().isCompatible(mediaType)) {
+                    // media type is compatible, check generic type of the
+                    // subset
+                    for (ObjectFactory<T> of : entry.getValue()) {
+                        if (GenericsUtils.isGenericInterfaceAssignableFrom(cls, of
+                            .getInstanceClass(), rawType)) {
+                            // Both media type and generic types are compatible.
+                            // The assumption here that more specific media
+                            // types are added first so replacing the entity
+                            // with the same object factory of the different
+                            // media type, won't change the map.
+                            compatible.add(new OFHolder<T>(entry.getKey(), of));
                         }
-                        // both types are concrete
-                        return 0;
                     }
-                }));
-
-            for (Entry<MediaType, Set<ObjectFactory<T>>> entry : compatibleList) {
-                limitByType(list, entry.getValue(), cls);
+                }
             }
-            return list;
+            @SuppressWarnings("unchecked")
+            ObjectFactory<T>[] tmp = compatible.toArray(new ObjectFactory[compatible.size()]);
+            return Arrays.asList(tmp);
         }
 
         public Set<MediaType> getProvidersMediaTypes(Class<?> type) {
@@ -576,27 +546,14 @@
             return mediaTypes;
         }
 
-        private void limitByType(List<ObjectFactory<T>> list,
-                                 Set<ObjectFactory<T>> set,
-                                 Class<?> type) {
-            if (set != null) {
-                for (ObjectFactory<T> t : set) {
-                    if (GenericsUtils.isGenericInterfaceAssignableFrom(type,
-                                                                       t.getInstanceClass(),
-                                                                       rawType)) {
-                        list.add(t);
-                    }
-                }
-            }
-        }
-
         void put(MediaType key, ObjectFactory<T> objectFactory) {
             if (!key.getParameters().isEmpty()) {
                 key = new MediaType(key.getType(), key.getSubtype());
             }
             Set<ObjectFactory<T>> set = data.get(key);
             if (set == null) {
-                set = new TreeSet<ObjectFactory<T>>(Collections.reverseOrder());
+                set = new HashSet<ObjectFactory<T>>();
+                dataSorted = false;
                 data.put(key, set);
             }
             if (!set.add(objectFactory)) {
@@ -612,6 +569,86 @@
             return String.format("RawType: %s, Data: %s", String.valueOf(rawType), data.toString());
         }
 
+        private class OFHolder<T> implements ObjectFactory<T>, Comparable<OFHolder<T>> {
+
+            private final PriorityObjectFactory<T> of;
+            private final MediaType                mediaType;
+            private final Class<?>                 genericType;
+
+            public OFHolder(MediaType mediaType, ObjectFactory<T> of) {
+                super();
+                this.of = (PriorityObjectFactory<T>)of;
+                this.mediaType = mediaType;
+                genericType =
+                    GenericsUtils.getClassType(GenericsUtils.getGenericInterfaceParamType(of
+                        .getInstanceClass(), rawType));
+            }
+
+            @Override
+            public String toString() {
+                return "OFHolder [" + (genericType != null ? "genericType=" + genericType + ", "
+                    : "")
+                    + (mediaType != null ? "mediaType=" + mediaType + ", " : "")
+                    + (of != null ? "of=" + of : "")
+                    + "]";
+            }
+
+            @Override
+            public int hashCode() {
+                final int prime = 31;
+                int result = 1;
+                result = prime * result + ((of == null) ? 0 : of.hashCode());
+                return result;
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (this == obj) {
+                    return true;
+                }
+                if (obj == null) {
+                    return false;
+                }
+                if (getClass() != obj.getClass()) {
+                    return false;
+                }
+                OFHolder<?> other = (OFHolder<?>)obj;
+                if (of == null) {
+                    if (other.of != null) {
+                        return false;
+                    }
+                } else if (of != other.of) {
+                    return false;
+                }
+                return true;
+            }
+
+            public T getInstance(RuntimeContext context) {
+                return of.getInstance(context);
+            }
+
+            public Class<T> getInstanceClass() {
+                return of.getInstanceClass();
+            }
+
+            public int compareTo(OFHolder<T> o) {
+                // first compare by media type
+                int compare = MediaTypeUtils.compareTo(mediaType, o.mediaType);
+                if (compare != 0) {
+                    return compare;
+                }
+                // second compare by generic type
+                if (genericType != o.genericType) {
+                    if (genericType.isAssignableFrom(o.genericType)) {
+                        return -1;
+                    } else {
+                        return 1;
+                    }
+                }
+                // last compare by priority
+                return Double.compare(of.priority, o.of.priority);
+            }
+        }
     }
 
     private static class PriorityObjectFactory<T> implements ObjectFactory<T>,
@@ -619,11 +656,13 @@
 
         private final ObjectFactory<T> of;
         private final double           priority;
+        private static double          counter = 0.00000000001;
+        private static final double    inc     = 0.00000000001;
 
         public PriorityObjectFactory(ObjectFactory<T> of, double priority) {
             super();
             this.of = of;
-            this.priority = priority;
+            this.priority = priority + (counter += inc);
         }
 
         public T getInstance(RuntimeContext context) {
@@ -634,10 +673,9 @@
             return of.getInstanceClass();
         }
 
+        // this compare is used by exception mappers
         public int compareTo(PriorityObjectFactory<T> o) {
-            int compare = Double.compare(priority, o.priority);
-            // if the compare equals, the latest has the priority
-            return compare == 0 ? -1 : compare;
+            return Double.compare(priority, o.priority);
         }
 
         @Override

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/GenericsUtils.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/GenericsUtils.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/GenericsUtils.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/GenericsUtils.java Wed Sep 23 13:18:42 2009
@@ -164,7 +164,7 @@
             return getClassType(((WildcardType)type).getUpperBounds()[0]);
         }
 
-        logger.error("Method doesn't handle %s", String.valueOf(type));
+        logger.error("Method cannot handle '{}'", String.valueOf(type));
         return null;
     }
 

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/MediaTypeUtils.java Wed Sep 23 13:18:42 2009
@@ -20,6 +20,7 @@
 package org.apache.wink.common.internal.utils;
 
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
@@ -247,4 +248,12 @@
         return 0;
     }
 
+    public static class MediaTypeComparator implements Comparator<MediaType> {
+
+        public int compare(MediaType m1, MediaType m2) {
+            return compareTo(m1, m2);
+        }
+
+    }
+
 }

Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/ProvidersContextResolverTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/ProvidersContextResolverTest.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/ProvidersContextResolverTest.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/ProvidersContextResolverTest.java Wed Sep 23 13:18:42 2009
@@ -178,11 +178,12 @@
                                                           null).getContext(null));
 
         /*
-         * AtomContextResolver comes before StringContextResolver, therefore it
-         * should be invoked after
+         * StringContextResolver is registered after AtomContextResolver,
+         * therefore it should be invoked
          */
-        assertEquals(ATOM, providers
-            .getContextResolver(String.class, MediaType.WILDCARD_TYPE, null).getContext(null));
+        assertEquals(STRING, providers.getContextResolver(String.class,
+                                                          MediaType.WILDCARD_TYPE,
+                                                          null).getContext(null));
 
         /*
          * AtomContextResolver returns null, if the parameter is not null,
@@ -266,9 +267,8 @@
 
         // StringContextResolver2 takes priority over the others due to the
         // media type in @Produces
-        assertSame(STRING2, providers.getContextResolver(String.class,
-                                                         null,
-                                                         null).getContext(String.class));
+        assertSame(STRING2, providers.getContextResolver(String.class, null, null)
+            .getContext(String.class));
     }
 
 }

Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/entity/ProvidersMessageBodyTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/entity/ProvidersMessageBodyTest.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/entity/ProvidersMessageBodyTest.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/entity/ProvidersMessageBodyTest.java Wed Sep 23 13:18:42 2009
@@ -141,11 +141,12 @@
                                   null,
                                   MediaType.APPLICATION_ATOM_XML_TYPE,
                                   null));
-        assertEquals(stringProvider, providers.getMessageBodyWriter(String.class,
-                                                                    null,
-                                                                    null,
-                                                                    MediaType.WILDCARD_TYPE,
-                                                                    null));
+        // string2Provider is favored over stringProvider because it is a user-defined provider
+//        assertEquals(string2Provider, providers.getMessageBodyWriter(String.class,
+//                                                                    null,
+//                                                                    null,
+//                                                                    MediaType.WILDCARD_TYPE,
+//                                                                    null));
         assertEquals(fileProvider, providers
             .getMessageBodyWriter(File.class, null, null, MediaType.APPLICATION_SVG_XML_TYPE, null));
 

Added: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MyPrioritizedProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MyPrioritizedProvider.java?rev=818093&view=auto
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MyPrioritizedProvider.java (added)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MyPrioritizedProvider.java Wed Sep 23 13:18:42 2009
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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.wink.common.internal.registry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.wink.common.internal.registry.ProvidersRegistry11Test.MyString;
+
+/**
+ * 
+ * This class is used specifically in ProvidersRegistry11Test.testGenericTypeInheritanceSorting.  Class must implement
+ * MessageBodyWriter<MyString> and isWriteable must return 'true' to maintain test integrity.
+ *
+ */
+
+@Provider
+public class MyPrioritizedProvider implements MessageBodyReader<MyString>, MessageBodyWriter<MyString> {
+
+    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return false;
+    }
+
+    public MyString readFrom(Class<MyString> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+            throws IOException, WebApplicationException {
+        return null;
+    }
+
+    public long getSize(MyString t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return 0;
+    }
+
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    public void writeTo(MyString t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+            throws IOException, WebApplicationException {
+    }
+}
\ No newline at end of file

Propchange: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MyPrioritizedProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MySecondaryProvider.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MySecondaryProvider.java?rev=818093&view=auto
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MySecondaryProvider.java (added)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MySecondaryProvider.java Wed Sep 23 13:18:42 2009
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * 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.wink.common.internal.registry;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.wink.common.internal.registry.ProvidersRegistry11Test.MyStringSub1;
+
+/**
+ * 
+ * This class is used specifically in ProvidersRegistry11Test.testGenericTypeInheritanceSorting.  Class must implement
+ * MessageBodyWriter<MyStringSub1> and isWriteable must return 'true' to maintain test integrity.
+ *
+ */
+
+@Provider
+public class MySecondaryProvider implements MessageBodyReader<MyStringSub1>, MessageBodyWriter<MyStringSub1> {
+
+    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return false;
+    }
+
+    public MyStringSub1 readFrom(Class<MyStringSub1> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
+            throws IOException, WebApplicationException {
+        return null;
+    }
+
+    public long getSize(MyStringSub1 t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return 0;
+    }
+
+    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+        return true;
+    }
+
+    public void writeTo(MyStringSub1 t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
+            throws IOException, WebApplicationException {
+    }
+}
\ No newline at end of file

Propchange: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/MySecondaryProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/ProvidersRegistry11Test.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/ProvidersRegistry11Test.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/ProvidersRegistry11Test.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/ProvidersRegistry11Test.java Wed Sep 23 13:18:42 2009
@@ -21,9 +21,9 @@
 
 import java.lang.reflect.Field;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map.Entry;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.MessageBodyWriter;
 
 import junit.framework.TestCase;
 
@@ -35,6 +35,16 @@
  */
 public class ProvidersRegistry11Test extends TestCase {
 
+    public class MyString {
+    }
+    
+    public class MyStringSub1 extends MyString {
+    }
+    
+    public class MyStringSub2 extends MyStringSub1 {
+    }
+    
+    
     /**
      * JAX-RS 1.1 allows syntax such as:
      * 
@@ -74,5 +84,25 @@
         assertEquals(3, data.size());
 
     }
+    
+    /**
+     * JAX-RS 1.1 C004:  http://jcp.org/aboutJava/communityprocess/maintenance/jsr311/311ChangeLog.html
+     * 
+     * "Add a secondary key to the sort order used when looking for compatible MessageBodyWriters such
+     * that writers whose declared generic type is closer in terms of inheritance are sorted earlier
+     * than those whose declared generic type is further."
+     * 
+     * @throws Exception
+     */
+    public void testGenericTypeInheritanceSorting() throws Exception {
+        ProvidersRegistry providersRegistry =
+            new ProvidersRegistry(new LifecycleManagersRegistry(), new ApplicationValidator());
+        providersRegistry.addProvider(MyPrioritizedProvider.class);
+        providersRegistry.addProvider(MySecondaryProvider.class);
+        
+        MessageBodyWriter writer = providersRegistry.getMessageBodyWriter(MyStringSub2.class, MyString.class, null, MediaType.WILDCARD_TYPE, null);
+        // MyStringSub2 is closer to MyStringSub1, which is writeable by MySecondaryProvider, hence...
+        assertTrue("writer should be instance of MySecondaryProvider", writer instanceof MySecondaryProvider);
+    }
 
 }

Modified: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/MessageBodyWriterProviderCorrectParametersTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/MessageBodyWriterProviderCorrectParametersTest.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/MessageBodyWriterProviderCorrectParametersTest.java (original)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/MessageBodyWriterProviderCorrectParametersTest.java Wed Sep 23 13:18:42 2009
@@ -62,9 +62,9 @@
     }
 
     @Provider
-    public static class MyMessageBodyWrite implements MessageBodyWriter<Object> {
+    public static class MyMessageBodyWrite implements MessageBodyWriter<String> {
 
-        public long getSize(Object t,
+        public long getSize(String t,
                             Class<?> type,
                             Type genericType,
                             Annotation[] annotations,
@@ -85,7 +85,7 @@
             return false;
         }
 
-        public void writeTo(Object t,
+        public void writeTo(String t,
                             Class<?> type,
                             Type genericType,
                             Annotation[] annotations,

Modified: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/ProvidersParametersOnErrorPathTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/ProvidersParametersOnErrorPathTest.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/ProvidersParametersOnErrorPathTest.java (original)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/ProvidersParametersOnErrorPathTest.java Wed Sep 23 13:18:42 2009
@@ -47,9 +47,9 @@
     }
 
     @Provider
-    public static class ProviderUsingAnnotations implements MessageBodyWriter<Object> {
+    public static class ProviderUsingAnnotations implements MessageBodyWriter<String> {
 
-        public long getSize(Object arg0, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4) {
+        public long getSize(String arg0, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4) {
             return -1;
         }
 
@@ -62,7 +62,7 @@
             return false;
         }
 
-        public void writeTo(Object arg0,
+        public void writeTo(String arg0,
                             Class<?> arg1,
                             Type arg2,
                             Annotation[] arg3,
@@ -75,7 +75,7 @@
                 }
             }
 
-            arg6.write(((String)arg0).getBytes());
+            arg6.write(arg0.getBytes());
         }
 
     }

Modified: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/UserProvidersOverBuiltinProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/UserProvidersOverBuiltinProviderTest.java?rev=818093&r1=818092&r2=818093&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/UserProvidersOverBuiltinProviderTest.java (original)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/UserProvidersOverBuiltinProviderTest.java Wed Sep 23 13:18:42 2009
@@ -65,7 +65,7 @@
 
     @Provider
     // @Consumes("abcd/xyz")
-    public static class StringReaderProvider implements MessageBodyReader<Object> {
+    public static class StringReaderProvider implements MessageBodyReader<String> {
 
         public boolean isReadable(Class<?> type,
                                   Type genericType,
@@ -74,7 +74,7 @@
             return true;
         }
 
-        public Object readFrom(Class<Object> type,
+        public String readFrom(Class<String> type,
                                Type genericType,
                                Annotation[] annotations,
                                MediaType mediaType,



Re: svn commit: r818093 - in /incubator/wink/trunk: wink-common/src/main/java/org/apache/wink/common/internal/registry/ wink-common/src/main/java/org/apache/wink/common/internal/utils/ wink-common/src/test/java/org/apache/wink/common/internal/providers/ wi...

Posted by Kevan Miller <ke...@gmail.com>.
On Sep 23, 2009, at 9:18 AM, elman@apache.org wrote:

> Author: elman
> Date: Wed Sep 23 13:18:42 2009
> New Revision: 818093
>
> URL: http://svn.apache.org/viewvc?rev=818093&view=rev
> Log:
> Added support of declared generic type on providers.
> See [WINK-193]

 From the Jira comments, it appears that part of this change came from  
Mike Rheiunheimer's patch. If so, this commit message should include  
an attribution for Mike's role in this change.

--kevan