You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by bl...@apache.org on 2010/02/11 00:53:54 UTC
svn commit: r908763 - in /incubator/wink/trunk:
wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/
wink-common/src/main/resources/org/apache/wink/common/internal/i18n/
wink-common/src/test/java/org/apache/wink/common/internal/...
Author: bluk
Date: Wed Feb 10 23:53:23 2010
New Revision: 908763
URL: http://svn.apache.org/viewvc?rev=908763&view=rev
Log:
Add support for inheritable annotations
For @Provider and @Path, allow them to be
on superclasses/interfaces.
Issue a warning for compatibility in
other environments.
See [WINK-245]
Thanks to Davanum Srinivas for reporting
the issue.
Added:
incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/InheritedProviderAnnTest.java (with props)
Modified:
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ProviderMetadataCollector.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/resources/org/apache/wink/common/internal/i18n/resource.properties
incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollectorTest.java
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ProviderMetadataCollector.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ProviderMetadataCollector.java?rev=908763&r1=908762&r2=908763&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ProviderMetadataCollector.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/registry/metadata/ProviderMetadataCollector.java Wed Feb 10 23:53:23 2010
@@ -26,18 +26,60 @@
import javax.ws.rs.core.Context;
import javax.ws.rs.ext.Provider;
+import org.apache.wink.common.internal.i18n.Messages;
import org.apache.wink.common.internal.registry.Injectable;
import org.apache.wink.common.internal.registry.InjectableFactory;
import org.apache.wink.common.internal.utils.GenericsUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class ProviderMetadataCollector extends AbstractMetadataCollector {
+ private static final Logger logger = LoggerFactory.getLogger(ProviderMetadataCollector.class);
+
private ProviderMetadataCollector(Class<?> clazz) {
super(clazz);
}
public static boolean isProvider(Class<?> cls) {
- return cls.getAnnotation(Provider.class) != null;
+ /*
+ * look for the Provider annotation on super classes (even though
+ * @Provider does not have @java.lang.annotation.Inherited) in order to
+ * promote better compatibility with expected behavior
+ */
+ // return cls.getAnnotation(Provider.class) != null;
+ if (cls == Object.class) {
+ return false;
+ }
+
+ if (cls.getAnnotation(Provider.class) != null) {
+ return true;
+ }
+
+ Class<?> declaringClass = cls;
+
+ while (!declaringClass.equals(Object.class)) {
+ // try a superclass
+ Class<?> superclass = declaringClass.getSuperclass();
+ if (superclass.getAnnotation(Provider.class) != null) {
+ // issue warning
+ logger.warn(Messages.getMessage("providerShouldBeAnnotatedDirectly", cls));
+ return true;
+ }
+
+ // try interfaces
+ Class<?>[] interfaces = declaringClass.getInterfaces();
+ for (Class<?> interfaceClass : interfaces) {
+ if (interfaceClass.getAnnotation(Provider.class) != null) {
+ // issue warning
+ logger.warn(Messages.getMessage("providerShouldBeAnnotatedDirectly", cls));
+ return true;
+ }
+ }
+ declaringClass = declaringClass.getSuperclass();
+ }
+
+ return false;
}
public static ClassMetadata collectMetadata(Class<?> clazz) {
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=908763&r1=908762&r2=908763&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 Wed Feb 10 23:53:23 2010
@@ -62,7 +62,33 @@
}
public static boolean isStaticResource(Class<?> cls) {
- return cls.getAnnotation(Path.class) != null;
+ if (cls.getAnnotation(Path.class) != null) {
+ return true;
+ }
+
+ Class<?> declaringClass = cls;
+
+ while (!declaringClass.equals(Object.class)) {
+ // try a superclass
+ Class<?> superclass = declaringClass.getSuperclass();
+ if (superclass.getAnnotation(Path.class) != null) {
+ // issue warning
+ logger.warn(Messages.getMessage("rootResourceShouldBeAnnotatedDirectly", cls));
+ return true;
+ }
+
+ // try interfaces
+ Class<?>[] interfaces = declaringClass.getInterfaces();
+ for (Class<?> interfaceClass : interfaces) {
+ if (interfaceClass.getAnnotation(Path.class) != null) {
+ // issue warning
+ logger.warn(Messages.getMessage("rootResourceShouldBeAnnotatedDirectly", cls));
+ return true;
+ }
+ }
+ declaringClass = declaringClass.getSuperclass();
+ }
+ return false;
}
public static boolean isDynamicResource(Class<?> cls) {
@@ -137,6 +163,30 @@
getMetadata().addPath(path.value());
return true;
}
+
+ Class<?> declaringClass = cls;
+
+ while (!declaringClass.equals(Object.class)) {
+ // try a superclass
+ Class<?> superclass = declaringClass.getSuperclass();
+ path = superclass.getAnnotation(Path.class);
+ if (path != null) {
+ getMetadata().addPath(path.value());
+ return true;
+ }
+
+ // try interfaces
+ Class<?>[] interfaces = declaringClass.getInterfaces();
+ for (Class<?> interfaceClass : interfaces) {
+ path = interfaceClass.getAnnotation(Path.class);
+ if (path != null) {
+ getMetadata().addPath(path.value());
+ return true;
+ }
+ }
+ declaringClass = declaringClass.getSuperclass();
+ }
+
return false;
}
@@ -164,7 +214,8 @@
for (Injectable id : methodMetadata.getFormalParameters()) {
if (id.getParamType() == Injectable.ParamType.ENTITY) {
logger
- .warn(Messages.getMessage("subresourceLocatorIllegalEntityParameter"),
+ .warn(Messages
+ .getMessage("subresourceLocatorIllegalEntityParameter"),
methodName);
continue F1;
}
@@ -174,7 +225,8 @@
if (!methodMetadata.getConsumes().isEmpty() || !methodMetadata
.getProduces().isEmpty()) {
logger
- .warn(Messages.getMessage("subresourceLocatorAnnotatedConsumesProduces"),
+ .warn(Messages
+ .getMessage("subresourceLocatorAnnotatedConsumesProduces"),
methodName);
}
getMetadata().getSubResourceLocators().add(methodMetadata);
@@ -271,15 +323,14 @@
// method/sub-resource locator,
// since there is at least one JAX-RS annotation on the method
if (metadata.getHttpMethod() == null && metadata.getPath() == null) {
- if(metadata.isEncoded() || defaultValue != null) {
+ if (metadata.isEncoded() || defaultValue != null) {
// property methods may have @Encoded or @DefaultValue but
// are not HTTP methods/paths
return null;
}
- logger
- .warn(Messages.getMessage("methodNotAnnotatedCorrectly"),
- method.getName(),
- method.getDeclaringClass().getCanonicalName());
+ logger.warn(Messages.getMessage("methodNotAnnotatedCorrectly"),
+ method.getName(),
+ method.getDeclaringClass().getCanonicalName());
return null;
}
Modified: incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties?rev=908763&r1=908762&r2=908763&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties (original)
+++ incubator/wink/trunk/wink-common/src/main/resources/org/apache/wink/common/internal/i18n/resource.properties Wed Feb 10 23:53:23 2010
@@ -130,4 +130,8 @@
restServletWinkApplicationInitParam=Using application classes {} named in init-param {}
restServletUseDeploymentConfigurationParam=Using deployment configuration class {} named in init-param {}
restServletUsePropertiesFileAtLocation=Using properties file at {} named in init-param {}
-adminServletRequestProcessorInitBeforeAdmin=Request processor should be initialized prior calling to admin servlet.
\ No newline at end of file
+adminServletRequestProcessorInitBeforeAdmin=Request processor should be initialized prior calling to admin servlet.
+
+rootResourceShouldBeAnnotatedDirectly=The root resource class {0} should be annotated directly. In environments where annotation scanning is done automatically without an Application sub-class, the class may not be detected as a root resource.
+providerShouldBeAnnotatedDirectly=The provider class {0} should be annotated directly. In environments where annotation scanning is done automatically without an Application sub-class, the class may not be detected as a provider.
+
Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollectorTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollectorTest.java?rev=908763&r1=908762&r2=908763&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollectorTest.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/registry/metadata/ResourceMetadataCollectorTest.java Wed Feb 10 23:53:23 2010
@@ -22,7 +22,6 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
-import java.util.Map.Entry;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -32,9 +31,6 @@
import junit.framework.TestCase;
-import org.apache.wink.common.internal.registry.metadata.ClassMetadata;
-import org.apache.wink.common.internal.registry.metadata.ResourceMetadataCollector;
-
public class ResourceMetadataCollectorTest extends TestCase {
@Path("/myresource")
@@ -50,6 +46,56 @@
}
}
+ @Path("superclassvalue")
+ public static class SuperResource {
+
+ }
+
+ public static class MySubclassResource extends SuperResource {
+
+ }
+
+ @Path("interfacevalue")
+ public static interface MyInterface {
+
+ }
+
+ public static class MyInterfaceImpl implements MyInterface {
+
+ }
+
+ public static class MySuperInterfaceImpl extends SuperResource implements MyInterface {
+
+ }
+
+ /**
+ * Tests that @Path is inheritable. This may not follow the JAX-RS
+ * specification so a warning will be issued.
+ *
+ * @throws Exception
+ */
+ public void testPathInheritance() throws Exception {
+ ClassMetadata classMetadata =
+ ResourceMetadataCollector.collectMetadata(MySubclassResource.class);
+ assertTrue(ResourceMetadataCollector.isResource(MySubclassResource.class));
+ assertFalse(ResourceMetadataCollector.isDynamicResource(MySubclassResource.class));
+ assertTrue(ResourceMetadataCollector.isStaticResource(MySubclassResource.class));
+ assertEquals("superclassvalue", classMetadata.getPath());
+
+ classMetadata = ResourceMetadataCollector.collectMetadata(MyInterfaceImpl.class);
+ assertTrue(ResourceMetadataCollector.isResource(MyInterfaceImpl.class));
+ assertFalse(ResourceMetadataCollector.isDynamicResource(MyInterfaceImpl.class));
+ assertTrue(ResourceMetadataCollector.isStaticResource(MyInterfaceImpl.class));
+ assertEquals("interfacevalue", classMetadata.getPath());
+
+ // superclass will take precedence over interface
+ classMetadata = ResourceMetadataCollector.collectMetadata(MySuperInterfaceImpl.class);
+ assertTrue(ResourceMetadataCollector.isResource(MySuperInterfaceImpl.class));
+ assertFalse(ResourceMetadataCollector.isDynamicResource(MySuperInterfaceImpl.class));
+ assertTrue(ResourceMetadataCollector.isStaticResource(MySuperInterfaceImpl.class));
+ assertEquals("superclassvalue", classMetadata.getPath());
+ }
+
/**
* JAX-RS 1.1 allows syntax such as:
*
@@ -69,7 +115,7 @@
HashSet<MediaType> expected = new HashSet<MediaType>(3);
expected.add(new MediaType("abcd", "efg"));
expected.add(new MediaType("hijk", "lmn")); // make sure whitespace is
- // ignored
+ // ignored
expected.add(new MediaType("opqr", "stu"));
assertEquals(expected, values);
Added: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/InheritedProviderAnnTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/InheritedProviderAnnTest.java?rev=908763&view=auto
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/InheritedProviderAnnTest.java (added)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/InheritedProviderAnnTest.java Wed Feb 10 23:53:23 2010
@@ -0,0 +1,118 @@
+/*
+ * 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.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+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 org.apache.wink.common.utils.ProviderUtils;
+import org.apache.wink.server.internal.servlet.MockServletInvocationTest;
+import org.apache.wink.test.mock.MockRequestConstructor;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+public class InheritedProviderAnnTest extends MockServletInvocationTest {
+
+ public static interface MyMessageBodyWriterInterface extends MessageBodyWriter<String> {
+
+ }
+
+ @Override
+ protected Class<?>[] getClasses() {
+ return new Class<?>[] {TestResource.class, TestProvider.class};
+ }
+
+ @Provider
+ @Produces("abcd/efgh")
+ public static class TestParentProvider implements MyMessageBodyWriterInterface {
+
+ public long getSize(String arg0, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4) {
+ return -1;
+ }
+
+ public boolean isWriteable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {
+ return String.class.equals(arg0);
+ }
+
+ public void writeTo(String arg0,
+ Class<?> arg1,
+ Type arg2,
+ Annotation[] arg3,
+ MediaType arg4,
+ MultivaluedMap<String, Object> arg5,
+ OutputStream arg6) throws IOException, WebApplicationException {
+ arg6.write("parent".getBytes(ProviderUtils.getCharset(arg4)));
+ }
+ }
+
+ public static class TestProvider extends TestParentProvider {
+
+ public void writeTo(String arg0,
+ Class<?> arg1,
+ Type arg2,
+ Annotation[] arg3,
+ MediaType arg4,
+ MultivaluedMap<String, Object> arg5,
+ OutputStream arg6) throws IOException, WebApplicationException {
+ arg6.write("child".getBytes(ProviderUtils.getCharset(arg4)));
+ }
+ }
+
+ @Path("/string")
+ public static class TestResource {
+
+ @GET
+ public String getForm() {
+ return "hello";
+ }
+ }
+
+ /**
+ * Tests that a {@link Provider} can be inherited from the superclass. While
+ * this is not required by the specification, it is in order to promote
+ * better compatibility with providers (i.e. Jackson) that expected this
+ * behavior.
+ *
+ * @throws Exception
+ */
+ public void testInheritedProvider() throws Exception {
+ MockHttpServletRequest request =
+ MockRequestConstructor.constructMockRequest("GET", "/string", MediaType.TEXT_PLAIN);
+ MockHttpServletResponse response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals("hello", response.getContentAsString());
+
+ request = MockRequestConstructor.constructMockRequest("GET", "/string", "abcd/efgh");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals("child", response.getContentAsString());
+ }
+}
Propchange: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/InheritedProviderAnnTest.java
------------------------------------------------------------------------------
svn:eol-style = native