wink-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r...@apache.org
Subject svn commit: r992311 - in /incubator/wink/trunk: wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ wink-common/src/main/java/org/apache/wink/common/internal/utils/ wink-common/src/test/java/org/apache/wink/common/internal/util...
Date Fri, 03 Sep 2010 14:32:37 GMT
Author: rott
Date: Fri Sep  3 14:32:37 2010
New Revision: 992311

URL: http://svn.apache.org/viewvc?rev=992311&view=rev
Log:
WINK-310: support inheritance for method signatures whose parent uses generic types

Added:
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/GenericInheritanceProviderTest.java
Modified:
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/MethodMetadata.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollector.java
    incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/utils/GenericsUtils.java
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/GenericsUtilsTest.java

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/MethodMetadata.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/MethodMetadata.java?rev=992311&r1=992310&r2=992311&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/MethodMetadata.java
(original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/MethodMetadata.java
Fri Sep  3 14:32:37 2010
@@ -28,8 +28,12 @@ import java.util.Set;
 import javax.ws.rs.core.MediaType;
 
 import org.apache.wink.common.internal.registry.Injectable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class MethodMetadata extends AbstractMetadata {
+    
+    private static final Logger logger = LoggerFactory.getLogger(MethodMetadata.class);
 
     private ClassMetadata    parent;
     private Method           reflectionMethod;
@@ -48,7 +52,9 @@ public class MethodMetadata extends Abst
     }
 
     public void setReflectionMethod(Method reflectionMethod) {
+        logger.trace("setReflectionMethod({}) entry", reflectionMethod);
         this.reflectionMethod = reflectionMethod;
+        logger.trace("setReflectionMethod() exit");
     }
 
     public String getHttpMethod() {
@@ -56,12 +62,20 @@ public class MethodMetadata extends Abst
     }
 
     public void setHttpMethod(String httpMethod) {
+        logger.trace("setHttpMethod({}) entry", httpMethod);
         this.httpMethod = httpMethod;
+        logger.trace("setHttpMethod() exit");
     }
 
     public List<Injectable> getFormalParameters() {
         return formalParameters;
     }
+    
+    public void setFormalParameters(List<Injectable> formalParameters) {
+        logger.trace("setFormalParameters({}) entry", formalParameters);
+        this.formalParameters = formalParameters;
+        logger.trace("setFormalParameters() exit");
+    }
 
     @Override
     public Set<MediaType> getConsumes() {

Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollector.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollector.java?rev=992311&r1=992310&r2=992311&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollector.java
(original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollector.java
Fri Sep  3 14:32:37 2010
@@ -200,10 +200,10 @@ public class ResourceMetadataCollector e
     private void parseMethods() {
         F1: for (Method method : getMetadata().getResourceClass().getMethods()) {
             Class<?> declaringClass = method.getDeclaringClass();
-            if (method.getDeclaringClass() == Object.class) {
+            if (declaringClass == Object.class) {
                 continue F1;
             }
-            MethodMetadata methodMetadata = createMethodMetadata(method);
+            MethodMetadata methodMetadata = createMethodMetadata(method, null);
             if (methodMetadata != null) {
                 String path = methodMetadata.getPath();
                 String httpMethod = methodMetadata.getHttpMethod();
@@ -248,16 +248,15 @@ public class ResourceMetadataCollector e
         }
     }
 
-    private MethodMetadata createMethodMetadata(Method method) {
+    private MethodMetadata createMethodMetadata(Method method, MethodMetadata implMethodMetadata)
{
 
         int modifiers = method.getModifiers();
         // only public, non-static methods
         if (Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
             return null;
         }
-
+        
         MethodMetadata metadata = new MethodMetadata(getMetadata());
-        metadata.setReflectionMethod(method);
 
         boolean hasAnnotation = false;
 
@@ -296,10 +295,21 @@ public class ResourceMetadataCollector e
             hasAnnotation = true;
         }
 
-        // if the method has not annotation at all,
+        if (implMethodMetadata == null) {
+            parseMethodParameters(method, metadata);
+            metadata.setReflectionMethod(method);
+        } else {
+            // 'method' being processed is a super (abstract or interface),
+            // but we already have some concrete metadata, so:
+            metadata.setFormalParameters(implMethodMetadata.getFormalParameters());
+            metadata.setReflectionMethod(implMethodMetadata.getReflectionMethod());
+        }
+    
+        // if the method has no annotation at all,
         // then it may override a method in a superclass or interface that has
         // annotations,
         // so try looking at the overridden method annotations
+        // but keep the method params as the super may have declared a generic type param
         if (!hasAnnotation) {
 
             Class<?> declaringClass = method.getDeclaringClass();
@@ -307,7 +317,7 @@ public class ResourceMetadataCollector e
             // try a superclass
             Class<?> superclass = declaringClass.getSuperclass();
             if (superclass != null && superclass != Object.class) {
-                MethodMetadata createdMetadata = createMethodMetadata(superclass, method);
+                MethodMetadata createdMetadata = createMethodMetadata(superclass, method,
implMethodMetadata);
                 // stop with if the method found
                 if (createdMetadata != null) {
                     return createdMetadata;
@@ -317,7 +327,7 @@ public class ResourceMetadataCollector e
             // try interfaces
             Class<?>[] interfaces = declaringClass.getInterfaces();
             for (Class<?> interfaceClass : interfaces) {
-                MethodMetadata createdMetadata = createMethodMetadata(interfaceClass, method);
+                MethodMetadata createdMetadata = createMethodMetadata(interfaceClass, method,
implMethodMetadata);
                 // stop with the first method found
                 if (createdMetadata != null) {
                     return createdMetadata;
@@ -345,20 +355,37 @@ public class ResourceMetadataCollector e
             return null;
         }
 
-        parseMethodParameters(method, metadata);
-
         return metadata;
     }
 
-    private MethodMetadata createMethodMetadata(Class<?> declaringClass, Method method)
{
+    private MethodMetadata createMethodMetadata(Class<?> declaringClass, Method method,
MethodMetadata implMethodMetadata) {
         try {
             Method declaredMethod =
                 declaringClass.getDeclaredMethod(method.getName(), method.getParameterTypes());
-            return createMethodMetadata(declaredMethod);
+            return createMethodMetadata(declaredMethod, implMethodMetadata);
         } catch (SecurityException e) {
             // can't get to overriding method
             return null;
         } catch (NoSuchMethodException e) {
+            // see if declaringClass's declaredMethod uses generic parameters
+            Method[] methods = declaringClass.getMethods();
+            for(Method candidateMethod: methods) {
+                if (candidateMethod.getName().equals(method.getName())) {
+                    // name matches, now check the param signature:
+                    if (candidateMethod.getParameterTypes().length == method.getParameterTypes().length)
{
+                        // so far so good.  Now make sure the params are acceptable:
+                        for (int i = 0; i < candidateMethod.getParameterTypes().length;
i++) {
+                            Class clazz = candidateMethod.getParameterTypes()[i];
+                            if (clazz.isPrimitive()) {
+                                break;  // signature doesn't match, otherwise it would have
been found in getDeclaredMethod above
+                            }
+                            if (clazz.isAssignableFrom(method.getParameterTypes()[i])) {
+                                return createMethodMetadata(candidateMethod, implMethodMetadata);
+                            }
+                        }
+                    }
+                }
+            }
             // no overriding method exists
             return null;
         }

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=992311&r1=992310&r2=992311&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
Fri Sep  3 14:32:37 2010
@@ -57,7 +57,9 @@ public class GenericsUtils {
                                                            Class<?> assignable,
                                                            Class<?> rawType) {
         Type genericType = GenericsUtils.getGenericInterfaceParamType(assignable, rawType);
-        return isAssignableFrom(genericType, cls);
+        // if genericType == null, assume developer did something like forgot to parameterize
+        // their interface, in which case the genericType is indeed assignable from cls
+        return (genericType == null) || isAssignableFrom(genericType, cls);
     }
 
     /**
@@ -126,6 +128,8 @@ public class GenericsUtils {
             }
             cls = cls.getSuperclass();
         }
+        // if we're done with the recursive calls, perhaps developer
+        // did not parameterize their interface
         return null;
     }
 

Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/GenericsUtilsTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/GenericsUtilsTest.java?rev=992311&r1=992310&r2=992311&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/GenericsUtilsTest.java
(original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/utils/GenericsUtilsTest.java
Fri Sep  3 14:32:37 2010
@@ -32,7 +32,7 @@ public class GenericsUtilsTest extends T
 
     public interface II {
     }
-
+    
     public abstract static class A implements List<String> {
 
         public List<String>         stringList;
@@ -63,11 +63,14 @@ public class GenericsUtilsTest extends T
         assertTrue(GenericsUtils.isAssignableFrom(A.class.getField("stringList").getGenericType(),
                                                   List.class));
     }
-
+    
     public void testIsGenericInterfaceAssignableFrom() {
         assertTrue(GenericsUtils
             .isGenericInterfaceAssignableFrom(String.class, B.class, List.class));
         assertTrue(GenericsUtils.isGenericInterfaceAssignableFrom(Integer.class, B.class,
I.class));
+        // II is not parameterized, but B is still assignableFrom because we
+        // assume developer just forgot to parameterize their interface:
+        assertTrue(GenericsUtils.isGenericInterfaceAssignableFrom(Integer.class, B.class,
II.class));
         assertTrue(GenericsUtils
             .isGenericInterfaceAssignableFrom(byte[].class, C.class, List.class));
         assertTrue(GenericsUtils.isGenericInterfaceAssignableFrom(List.class, L.class, List.class));

Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/GenericInheritanceProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/GenericInheritanceProviderTest.java?rev=992311&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/GenericInheritanceProviderTest.java
(added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/GenericInheritanceProviderTest.java
Fri Sep  3 14:32:37 2010
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * 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.server.internal.providers.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Provider;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.wink.server.internal.servlet.MockServletInvocationTest;
+import org.apache.wink.test.mock.MockRequestConstructor;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+
+public class GenericInheritanceProviderTest extends MockServletInvocationTest {
+
+    private static boolean reachedNirvana = false;
+    
+    @XmlAccessorType(XmlAccessType.FIELD)
+    @XmlType(name="MyJAXBObject", propOrder = {"stringdata"})
+    @XmlRootElement(name = "myJAXBObject")
+    public static class MyJAXBObject {
+        private String stringdata;
+        public MyJAXBObject() {}
+        public void setStringdata(String stringdata) {
+            this.stringdata = stringdata;
+        }
+        public String getStringdata() {
+            return stringdata;
+        }
+    }
+    
+    public static interface GenericService<T> {
+        @POST
+        @Consumes(MediaType.APPLICATION_JSON)
+        public void doSomething(T obj);
+    }
+
+    @Path("/impl")
+    public static class GenericServiceImpl implements GenericService<MyJAXBObject>
{
+        public void doSomething(MyJAXBObject obj) {
+            reachedNirvana = true;
+        }
+    }
+    
+    @Provider
+    @Consumes(MediaType.APPLICATION_JSON)
+    public static class JSONtoJAXBProvider implements MessageBodyReader {
+
+        public boolean isReadable(Class type, Type genericType,
+                Annotation[] annotations, MediaType mediaType) {
+            return mediaType.equals(MediaType.APPLICATION_JSON_TYPE);
+        }
+
+        public Object readFrom(Class type, Type genericType,
+                Annotation[] annotations, MediaType mediaType,
+                MultivaluedMap httpHeaders, InputStream entityStream)
+                throws IOException {
+            // for test purposes, I don't really care about how this conversion is actually
done, just
+            // that Wink can navigate its way through the right paths and providers
+            return new MyJAXBObject();
+        }
+        
+    }
+    
+    @Override
+    protected Class<?>[] getClasses() {
+        return new Class<?>[] {GenericServiceImpl.class, JSONtoJAXBProvider.class};
+    }
+    
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        reachedNirvana = false;
+    }
+    
+    @Test
+    public void test() throws Exception {
+        MockHttpServletRequest request =
+            MockRequestConstructor.constructMockRequest("POST",
+                                                        "/impl",
+                                                        MediaType.TEXT_PLAIN,
+                                                        MediaType.APPLICATION_JSON,
+                                                        "{stringdata: \"hi\"}".getBytes());
+        invoke(request);
+        assertTrue(reachedNirvana);
+    }
+
+}



Mime
View raw message