/******************************************************************************* * Copyright (c) 2012-2016 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.everrest.core.impl.resource; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Appender; import org.everrest.core.BaseObjectModel; import org.everrest.core.ConstructorDescriptor; import org.everrest.core.FieldInjector; import org.everrest.core.Parameter; import org.everrest.core.resource.ResourceDescriptor; import org.everrest.core.resource.ResourceMethodDescriptor; import org.everrest.core.resource.SubResourceLocatorDescriptor; import org.everrest.core.resource.SubResourceMethodDescriptor; import org.everrest.core.uri.UriPattern; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; import org.slf4j.LoggerFactory; import javax.annotation.security.PermitAll; import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; import javax.ws.rs.DefaultValue; import javax.ws.rs.Encoded; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Request; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; import java.util.List; import java.util.Map; import static com.google.common.collect.Lists.newArrayList; import static java.util.stream.Collectors.toList; import static javax.ws.rs.core.MediaType.WILDCARD_TYPE; import static org.everrest.core.util.ParameterizedTypeImpl.newParameterizedType; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * @author andrew00x */ public class AbstractResourceDescriptorTest { @Rule public ExpectedException thrown = ExpectedException.none(); private Appender<ILoggingEvent> mockLogbackAppender; @Before public void setUp() throws Exception { setUpLogbackAppender(); } private void setUpLogbackAppender() { ch.qos.logback.classic.Logger resourceDescriptorLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(AbstractResourceDescriptor.class); ch.qos.logback.classic.Logger baseObjectModelLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BaseObjectModel.class); mockLogbackAppender = mockLogbackAppender(); resourceDescriptorLogger.addAppender(mockLogbackAppender); baseObjectModelLogger.addAppender(mockLogbackAppender); } private Appender mockLogbackAppender() { Appender mockAppender = mock(Appender.class); when(mockAppender.getName()).thenReturn("MockAppender"); return mockAppender; } @After public void tearDown() { ch.qos.logback.classic.Logger resourceDescriptorLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(AbstractResourceDescriptor.class); ch.qos.logback.classic.Logger baseObjectModelLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BaseObjectModel.class); resourceDescriptorLogger.detachAppender(mockLogbackAppender); baseObjectModelLogger.detachAppender(mockLogbackAppender); } @Test public void failsWhenResourceDoesNotHavePublicConstructor() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(NoPublicConstructorResource.class); } @Path("a") public static class NoPublicConstructorResource { NoPublicConstructorResource() {} @GET public void m1() {} } @Test public void warnWhenResourceDoesNotHaveAnyJaxRsMethods() { AbstractResourceDescriptor resourceDescriptor = new AbstractResourceDescriptor(NoJaxRsMethodResourceResource.class); assertEquals(1, resourceDescriptor.getResourceMethods().size()); assertNotNull(resourceDescriptor.getResourceMethods().get("OPTIONS")); assertTrue(resourceDescriptor.getSubResourceMethods().isEmpty()); assertTrue(resourceDescriptor.getSubResourceLocators().isEmpty()); assertTrue(retrieveLoggingEvents().stream().anyMatch(loggingEvent -> loggingEvent.getLevel() == Level.WARN && loggingEvent.getMessage().equals("Not found any resource methods, sub-resource methods or sub-resource locators in {}"))); } @Path("a") public static class NoJaxRsMethodResourceResource { public void m1() {} } private List<ILoggingEvent> retrieveLoggingEvents() { ArgumentCaptor<ILoggingEvent> logEventCaptor = ArgumentCaptor.forClass(ILoggingEvent.class); verify(mockLogbackAppender, atLeastOnce()).doAppend(logEventCaptor.capture()); return logEventCaptor.getAllValues(); } @Test public void failsWhenResourceClassHasTwoMethodsWithSameHttpMethodAnnotations() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithTwoMethodsWithSameHttpMethodAnnotations.class); } @Path("a") public static class ResourceWithTwoMethodsWithSameHttpMethodAnnotations { @GET public void m1() {} @GET public void m2() {} } @Test public void failsWhenResourceClassHasTwoMethodsWithSameHttpMethodConsumesAndProducesAnnotations() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithTwoMethodsWithSameHttpMethodConsumesAndProducesAnnotations.class); } @Path("a") public static class ResourceWithTwoMethodsWithSameHttpMethodConsumesAndProducesAnnotations { @GET @Consumes({"text/xml", "application/xml", "application/xml+xhtml"}) @Produces("text/plain") public void m1() {} @GET @Consumes({"application/xml", "text/xml", "application/xml+xhtml"}) @Produces("text/plain") public void m2() {} } @Test public void failsWhenResourceClassHasTwoMethodsWithSameHttpMethodAndPathAnnotations() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithTwoMethodsWithSameHttpMethodAndPathAnnotations.class); } @Path("a") public static class ResourceWithTwoMethodsWithSameHttpMethodAndPathAnnotations { @GET @Path("b") public void m1() {} @GET @Path("/b") public void m2() {} } @Test public void failsWhenResourceClassHasTwoMethodsWithSameHttpMethodConsumesProducesAndPathAnnotations() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithTwoMethodsWithSameHttpMethodConsumesProducesAndPathAnnotations.class); } @Path("a") public static class ResourceWithTwoMethodsWithSameHttpMethodConsumesProducesAndPathAnnotations { @GET @Consumes({"text/xml", "application/xml", "application/xml+xhtml"}) @Produces("text/plain") @Path("b") public void m1() {} @GET @Consumes({"application/xml", "text/xml", "application/xml+xhtml"}) @Produces("text/plain") @Path("b") public void m2() {} } @Test public void failsWhenResourceClassHasTwoMethodsWithSamePathAnnotations() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithTwoMethodsWithSamePathAnnotations.class); } @Path("/a") public static class ResourceWithTwoMethodsWithSamePathAnnotations { @Path("b") public Object m1() {return new Object();} @Path("/b") public Object m2() {return new Object();} } @Test public void failsWhenResourceHasMethodWithTwoJaxRsAnnotationsOnSameParameter() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithMethodWithTwoJaxRsAnnotationsOnSameParameter.class); } @Path("/a") public static class ResourceWithMethodWithTwoJaxRsAnnotationsOnSameParameter { @GET @Path("b") public void m1(@PathParam("b") @HeaderParam("h1") String b) {} } @Test public void failsWhenResourceHasConstructorWithTwoJaxRsAnnotationsOnSameParameter() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithConstructorWithTwoJaxRsAnnotationsOnSameParameter.class); } @Path("/a") public static class ResourceWithConstructorWithTwoJaxRsAnnotationsOnSameParameter { public ResourceWithConstructorWithTwoJaxRsAnnotationsOnSameParameter(@PathParam("b") @HeaderParam("h1") String b) {} @GET public void m1() {} } @Test public void failsWhenResourceHasFieldWithTwoJaxRsAnnotations() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithFieldThatHasTwoJaxRsAnnotations.class); } @Path("/a") public static class ResourceWithFieldThatHasTwoJaxRsAnnotations { @PathParam("b") @QueryParam("query") String s; @GET public void m1() {} } @Test public void failsWhenResourceMethodHasMoreThanOneEntityParameter() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithMethodThatHasMoreThanOneEntityParameter.class); } @Path("a") public static class ResourceWithMethodThatHasMoreThanOneEntityParameter { @POST public void m1(String entityOne, String entityTwo){} } @Test public void failsWhenResourceMethodHasAtLeastOneFormParamAndEntityParameterOtherThanMultivaluedMap() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithMethodThatHasAtLeastOneFormParamAndEntityParameterOtherThanMultivaluedMap.class); } @Path("a") public static class ResourceWithMethodThatHasAtLeastOneFormParamAndEntityParameterOtherThanMultivaluedMap { @POST public void m1(@FormParam("x") String formParam, String entity){} } @Test public void failsWhenResourceLocatorHasEntityParameter() { thrown.expect(RuntimeException.class); new AbstractResourceDescriptor(ResourceWithResourceLocatorThatHasEntityParameter.class); } @Path("a") public static class ResourceWithResourceLocatorThatHasEntityParameter { @Path("b") public Object m1(String entity){return null;} } @Test public void warnWhenResourceHasTwoConstructorsWithTheSameNumberOfParameters() { new AbstractResourceDescriptor(ResourceWithTwoConstructorsWithTheSameNumberOfParameters.class); assertTrue(retrieveLoggingEvents().stream().anyMatch(loggingEvent -> loggingEvent.getLevel() == Level.WARN && loggingEvent.getMessage().equals("Two constructors with the same number of parameter found {} and {}"))); } @Path("/a") public static class ResourceWithTwoConstructorsWithTheSameNumberOfParameters { public ResourceWithTwoConstructorsWithTheSameNumberOfParameters(@PathParam("b") String b, @QueryParam("c") int c) {} public ResourceWithTwoConstructorsWithTheSameNumberOfParameters(@HeaderParam("a") int a, @PathParam("d") String d) {} @GET public void m1() {} } @Test public void warnWhenResourceHasNonPublicJaxRsMethods() { new AbstractResourceDescriptor(ResourceWithNonPublicJaxRsMethod.class); assertTrue(retrieveLoggingEvents().stream().anyMatch(loggingEvent -> loggingEvent.getLevel() == Level.WARN && loggingEvent.getMessage().equals("Non-public method {} in {} annotated with @Path of HTTP method annotation, it's ignored"))); } @Path("/") public static class ResourceWithNonPublicJaxRsMethod { @GET void nonPublicGET_method() {} } @Test public void processesRootResource() { ResourceDescriptor rootResource = new AbstractResourceDescriptor(SampleRootResource.class); assertEquals(SampleRootResource.class, rootResource.getObjectClass()); assertTrue(rootResource.isRootResource()); assertEquals("/a/{b}/", rootResource.getPathValue().getPath()); } @Test public void processesNonRootResource() { ResourceDescriptor nonRootResource = new AbstractResourceDescriptor(SampleNonRootResource.class); assertEquals(SampleNonRootResource.class, nonRootResource.getObjectClass()); assertFalse(nonRootResource.isRootResource()); assertNull(nonRootResource.getPathValue()); } @Test public void processesFields() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); List<FieldInjector> fieldInjectors = filterFieldsInsertedByJacocoFrameworkDuringInstrumentation(resource.getFieldInjectors()); assertEquals(1, fieldInjectors.size()); FieldInjector fieldInjector = fieldInjectors.get(0); assertEquals(String.class, fieldInjector.getParameterClass()); assertEquals(String.class, fieldInjector.getGenericType()); assertEquals("default", fieldInjector.getDefaultValue()); assertEquals(PathParam.class, fieldInjector.getAnnotation().annotationType()); assertEquals("b", ((PathParam)fieldInjector.getAnnotation()).value()); assertTrue(fieldInjector.isEncoded()); } @Test public void processesFieldsFromSuperClasses() { ResourceDescriptor resource = new AbstractResourceDescriptor(EndResource.class); List<FieldInjector> fieldInjectors = filterFieldsInsertedByJacocoFrameworkDuringInstrumentation(resource.getFieldInjectors()); List<String> fieldNames = fieldInjectors.stream().map(FieldInjector::getName).collect(toList()); assertEquals(4, fieldNames.size()); assertTrue(fieldNames.containsAll(newArrayList("uriInfo", "request", "securityContext", "headers"))); } public abstract static class AbstractResource { @Context protected UriInfo uriInfo; @Context protected Request request; } public abstract static class ExtResource extends AbstractResource { @Context protected SecurityContext securityContext; } public static class EndResource extends ExtResource { @Context private HttpHeaders headers; @GET public void m1() {} } @Test public void processesConstructors() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); assertEquals(3, resource.getConstructorDescriptors().size()); List<ConstructorDescriptor> constructors = resource.getConstructorDescriptors(); assertEquals(2, constructors.get(0).getParameters().size()); assertEquals(1, constructors.get(1).getParameters().size()); assertEquals(0, constructors.get(2).getParameters().size()); ConstructorDescriptor constructorWithTheMostParameters = constructors.get(0); List<Parameter> constructorParameters = constructorWithTheMostParameters.getParameters(); assertEquals(int.class, constructorParameters.get(0).getParameterClass()); assertEquals(String.class, constructorParameters.get(1).getParameterClass()); assertEquals(QueryParam.class, constructorParameters.get(0).getAnnotation().annotationType()); assertEquals(PathParam.class, constructorParameters.get(1).getAnnotation().annotationType()); assertEquals("test", ((QueryParam)constructorParameters.get(0).getAnnotation()).value()); assertEquals("b", ((PathParam)constructorParameters.get(1).getAnnotation()).value()); assertFalse(constructorParameters.get(0).isEncoded()); assertTrue(constructorParameters.get(1).isEncoded()); } @Test public void processesAllMethods() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); assertEquals(3, resource.getResourceMethods().size()); assertEquals(1, resource.getSubResourceMethods().size()); assertEquals(1, resource.getSubResourceLocators().size()); } @Test public void adds_OPTIONS_HttpMethodThatGenerated_WADL_Response() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); assertNotNull(resource.getResourceMethods().get("OPTIONS")); assertEquals(1, resource.getResourceMethods().get("OPTIONS").size()); ResourceMethodDescriptor methodDescriptor = resource.getResourceMethods().get("OPTIONS").get(0); assertNull(methodDescriptor.getMethod()); assertEquals("OPTIONS", methodDescriptor.getHttpMethod()); assertEquals(newArrayList(WILDCARD_TYPE), methodDescriptor.consumes()); assertEquals(newArrayList(new MediaType("application", "vnd.sun.wadl+xml")), methodDescriptor.produces()); assertEquals(SampleRootResource.class, methodDescriptor.getParentResource().getObjectClass()); assertTrue(methodDescriptor.getMethodParameters().isEmpty()); } @Test public void processesResourceMethods() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); assertNotNull(resource.getResourceMethods().get("GET")); assertEquals(1, resource.getResourceMethods().get("GET").size()); ResourceMethodDescriptor methodDescriptor = resource.getResourceMethods().get("GET").get(0); assertEquals("resourceMethod", methodDescriptor.getMethod().getName()); assertEquals("GET", methodDescriptor.getHttpMethod()); assertEquals(newArrayList(WILDCARD_TYPE), methodDescriptor.consumes()); assertEquals(newArrayList(new MediaType("application", "xml")), methodDescriptor.produces()); assertEquals(SampleRootResource.class, methodDescriptor.getParentResource().getObjectClass()); assertEquals(1, methodDescriptor.getMethodParameters().size()); Parameter methodParameter = methodDescriptor.getMethodParameters().get(0); assertEquals(String.class, methodParameter.getParameterClass()); assertEquals(PathParam.class, methodParameter.getAnnotations()[0].annotationType()); assertEquals(DefaultValue.class, methodParameter.getAnnotations()[1].annotationType()); assertEquals("hello", methodParameter.getDefaultValue()); assertEquals(PathParam.class, methodParameter.getAnnotation().annotationType()); assertEquals("b", ((PathParam)methodParameter.getAnnotation()).value()); } @Test public void adds_HEAD_HttpMethodFor_GET_ResourceMethod() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); assertNotNull(resource.getResourceMethods().get("HEAD")); assertEquals(1, resource.getResourceMethods().get("HEAD").size()); ResourceMethodDescriptor methodDescriptor = resource.getResourceMethods().get("HEAD").get(0); assertEquals("resourceMethod", methodDescriptor.getMethod().getName()); assertEquals("HEAD", methodDescriptor.getHttpMethod()); assertEquals(newArrayList(WILDCARD_TYPE), methodDescriptor.consumes()); assertEquals(newArrayList(new MediaType("application", "xml")), methodDescriptor.produces()); assertEquals(SampleRootResource.class, methodDescriptor.getParentResource().getObjectClass()); assertEquals(1, methodDescriptor.getMethodParameters().size()); Parameter methodParameter = methodDescriptor.getMethodParameters().get(0); assertEquals(String.class, methodParameter.getParameterClass()); assertEquals(PathParam.class, methodParameter.getAnnotations()[0].annotationType()); assertEquals(DefaultValue.class, methodParameter.getAnnotations()[1].annotationType()); assertEquals("hello", methodParameter.getDefaultValue()); assertEquals(PathParam.class, methodParameter.getAnnotation().annotationType()); assertEquals("b", ((PathParam)methodParameter.getAnnotation()).value()); } @Test public void processesSubResourceMethods() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); Map<String, List<SubResourceMethodDescriptor>> methods = resource.getSubResourceMethods().get(new UriPattern("{any}")); assertNotNull(methods.get("POST")); assertEquals(1, methods.get("POST").size()); SubResourceMethodDescriptor subResourceMethod = methods.get("POST").get(0); assertEquals("subResourceMethod", subResourceMethod.getMethod().getName()); assertEquals("POST", subResourceMethod.getHttpMethod()); assertEquals("{c}", subResourceMethod.getPathValue().getPath()); assertEquals(newArrayList(new MediaType("text", "plain"), new MediaType("text", "xml")), subResourceMethod.consumes()); assertEquals(newArrayList(new MediaType("text", "html")), subResourceMethod.produces()); assertEquals(SampleRootResource.class, subResourceMethod.getParentResource().getObjectClass()); assertEquals(1, subResourceMethod.getMethodParameters().size()); Parameter methodParameter = subResourceMethod.getMethodParameters().get(0); assertEquals(String.class, methodParameter.getParameterClass()); assertEquals(1, methodParameter.getAnnotations().length); assertEquals(PathParam.class, methodParameter.getAnnotations()[0].annotationType()); assertEquals(null, methodParameter.getDefaultValue()); assertEquals(PathParam.class, methodParameter.getAnnotation().annotationType()); assertNotNull(methods.get("GET")); assertEquals(1, methods.get("GET").size()); subResourceMethod = methods.get("GET").get(0); assertEquals("subResourceMethod", subResourceMethod.getMethod().getName()); assertEquals("GET", subResourceMethod.getHttpMethod()); assertEquals("{d}", subResourceMethod.getPathValue().getPath()); assertEquals(newArrayList(WILDCARD_TYPE), subResourceMethod.consumes()); assertEquals(newArrayList(WILDCARD_TYPE), subResourceMethod.produces()); assertEquals(SampleRootResource.class, subResourceMethod.getParentResource().getObjectClass()); assertEquals(1, subResourceMethod.getMethodParameters().size()); methodParameter = subResourceMethod.getMethodParameters().get(0); assertEquals(List.class, methodParameter.getParameterClass()); assertEquals(newParameterizedType(List.class, String.class), methodParameter.getGenericType()); assertEquals(1, methodParameter.getAnnotations().length); assertEquals(PathParam.class, methodParameter.getAnnotations()[0].annotationType()); assertEquals(null, methodParameter.getDefaultValue()); assertEquals(PathParam.class, methodParameter.getAnnotation().annotationType()); } @Test public void adds_HEAD_HttpMethodFor_GET_SubResourceMethod() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); Map<String, List<SubResourceMethodDescriptor>> methods = resource.getSubResourceMethods().get(new UriPattern("{any}")); assertNotNull(methods.get("HEAD")); assertEquals(1, methods.get("HEAD").size()); SubResourceMethodDescriptor subResourceMethod = methods.get("HEAD").get(0); assertEquals("subResourceMethod", subResourceMethod.getMethod().getName()); assertEquals("HEAD", subResourceMethod.getHttpMethod()); assertEquals("{d}", subResourceMethod.getPathValue().getPath()); assertEquals(newArrayList(WILDCARD_TYPE), subResourceMethod.consumes()); assertEquals(newArrayList(WILDCARD_TYPE), subResourceMethod.produces()); assertEquals(SampleRootResource.class, subResourceMethod.getParentResource().getObjectClass()); assertEquals(1, subResourceMethod.getMethodParameters().size()); Parameter methodParameter = subResourceMethod.getMethodParameters().get(0); assertEquals(List.class, methodParameter.getParameterClass()); assertEquals(newParameterizedType(List.class, String.class), methodParameter.getGenericType()); assertEquals(1, methodParameter.getAnnotations().length); assertEquals(PathParam.class, methodParameter.getAnnotations()[0].annotationType()); assertEquals(null, methodParameter.getDefaultValue()); assertEquals(PathParam.class, methodParameter.getAnnotation().annotationType()); } @Test public void processesSubResourceLocators() { ResourceDescriptor resource = new AbstractResourceDescriptor(SampleRootResource.class); SubResourceLocatorDescriptor subResourceLocator = resource.getSubResourceLocators().get(new UriPattern("{any}/d")); assertEquals("subResourceLocator", subResourceLocator.getMethod().getName()); assertEquals("{c}/d", subResourceLocator.getPathValue().getPath()); assertEquals(SampleRootResource.class, subResourceLocator.getParentResource().getObjectClass()); assertEquals(1, subResourceLocator.getMethodParameters().size()); Parameter methodParameter = subResourceLocator.getMethodParameters().get(0); assertEquals(String.class, methodParameter.getParameterClass()); assertEquals(2, methodParameter.getAnnotations().length); assertEquals(PathParam.class, methodParameter.getAnnotations()[0].annotationType()); assertEquals(Encoded.class, methodParameter.getAnnotations()[1].annotationType()); assertTrue(methodParameter.isEncoded()); assertEquals(null, methodParameter.getDefaultValue()); assertEquals(PathParam.class, methodParameter.getAnnotation().annotationType()); } @SuppressWarnings("unused") @Path("/a/{b}/") public static class SampleRootResource { @DefaultValue("default") @PathParam("b") @Encoded private String field; public SampleRootResource(@PathParam("b") String str) {} public SampleRootResource() {} public SampleRootResource(@QueryParam("test") int i, @Encoded @PathParam("b") String str) {} @POST @Path("{c}") @Consumes({"text/plain", "text/xml"}) @Produces({"text/html"}) public void subResourceMethod(@PathParam("b") String str) {} @GET @Path("{d}") public void subResourceMethod(@PathParam("b") List<String> list) {} @Path("{c}/d") public void subResourceLocator(@PathParam("b") @Encoded String str) {} @GET @Produces({"application/xml"}) public void resourceMethod(@PathParam("b") @DefaultValue("hello") String str) {} } public static class SampleNonRootResource { @GET public void resourceMethod() {} } @Test public void sortsResourceMethodsByConsumesAndProducesTypes() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceForTestSortingOfResourceMethods.class); List<String> methodNames = resource.getResourceMethods().get("GET").stream().map(resourceMethod -> resourceMethod.getMethod().getName()).collect(toList()); assertEquals(newArrayList("first", "second", "third", "fourth", "fifth", "last"), methodNames); } @Path("a") public static class ResourceForTestSortingOfResourceMethods { @Consumes({"application/*", "application/xml", "text/*"}) @Produces({"text/plain", "text/html", "text/*"}) @GET public void fifth() {} @GET public void last() {} @Consumes({"application/*", "text/*"}) @Produces({"text/plain", "text/html"}) @GET public void third() {} @Consumes({"application/xml", "text/plain"}) @GET public void second() {} @Consumes({"application/xml"}) @GET public void first() {} @Consumes({"text/*"}) @Produces({"text/html", "text/*"}) @GET public void fourth() {} } @Test public void sortsSubResourceMethodsByUriPatterAndConsumesAndProducesTypes() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceForTestSortingOfSubResourceMethods.class); Map<UriPattern, Map<String, List<SubResourceMethodDescriptor>>> subResourceMethods = resource.getSubResourceMethods(); assertEquals(newArrayList("/b/c/d", "/b/c", "/b/{c}", "/b"), subResourceMethods.keySet().stream().map(UriPattern::getTemplate).collect(toList())); assertEquals(1, subResourceMethods.get(new UriPattern("/b/c/d")).get("GET").size()); assertEquals(1, subResourceMethods.get(new UriPattern("/b/c")).get("GET").size()); assertEquals(1, subResourceMethods.get(new UriPattern("/b/{c}")).get("GET").size()); assertEquals(3, subResourceMethods.get(new UriPattern("/b")).get("GET").size()); List<String> methodNames = subResourceMethods.get(new UriPattern("/b")).get("GET").stream().map(subResourceMethod -> subResourceMethod.getMethod().getName()).collect(toList()); assertEquals(newArrayList("m2", "m5", "m0"), methodNames); } @Path("a") public static class ResourceForTestSortingOfSubResourceMethods { @Consumes({"application/*", "application/xml", "text/*"}) @Produces({"text/plain", "text/html", "text/*"}) @GET @Path("b") public void m0() {} @GET @Path("b/c") public void m1() {} @Consumes({"application/*", "text/*"}) @Produces({"text/plain", "text/html"}) @GET @Path("b") public void m2() {} @Consumes({"application/xml", "text/plain"}) @GET @Path("b/{c}") public void m3() {} @Consumes({"application/xml"}) @GET @Path("b/c/d") public void m4() {} @Consumes({"text/*"}) @Produces({"text/html", "text/*"}) @GET @Path("b") public void m5() {} } @Test public void sortsSubResourceLocatorsByUriPatter() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceForTestSortingOfSubResourceLocators.class); Map<UriPattern, SubResourceLocatorDescriptor> resourceLocators = resource.getSubResourceLocators(); assertEquals(newArrayList("/b/c/d", "/b/c/z", "/b/c", "/b/{c}", "/b"), resourceLocators.keySet().stream().map(UriPattern::getTemplate).collect(toList())); } @Path("a") public static class ResourceForTestSortingOfSubResourceLocators { @Path("b") public void m0() {} @Path("b/c/z") public void m1() {} @Path("b/{c}") public void m2() {} @Path("b/c/d") public void m3() {} @Path("b/c") public void m4() {} } @Test public void inheritsJaxRsAnnotationFromImplementedInterfaces() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceImpl.class); Map<String, List<SubResourceMethodDescriptor>> methods = resource.getSubResourceMethods().get(new UriPattern("b")); assertNotNull(methods.get("GET")); assertEquals(1, methods.get("GET").size()); SubResourceMethodDescriptor subResourceMethod = methods.get("GET").get(0); assertEquals("m1", subResourceMethod.getMethod().getName()); assertEquals("GET", subResourceMethod.getHttpMethod()); assertEquals("b", subResourceMethod.getPathValue().getPath()); assertEquals(newArrayList(new MediaType("text", "plain")), subResourceMethod.consumes()); assertEquals(newArrayList(WILDCARD_TYPE), subResourceMethod.produces()); assertEquals(ResourceImpl.class, subResourceMethod.getParentResource().getObjectClass()); assertEquals(1, subResourceMethod.getMethodParameters().size()); Parameter methodParameter = subResourceMethod.getMethodParameters().get(0); assertEquals(String.class, methodParameter.getParameterClass()); assertEquals(0, methodParameter.getAnnotations().length); assertEquals(null, methodParameter.getDefaultValue()); } public interface Resource { @Consumes({"text/plain"}) @GET void m1(String entity); } @Path("a") public static class ResourceImpl implements Resource { @Path("b") @Override public void m1(String entity) {} } @Test public void processesSecurityAnnotationFromMethod() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithMethodWithSecurityAnnotation.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); RolesAllowed rolesAllowed = (RolesAllowed)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(rolesAllowed); } @Path("a") public static class ResourceWithMethodWithSecurityAnnotation { @RolesAllowed("user") @GET public void m1() {} } @Test public void processesSecurityAnnotationFromClass() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithSecurityAnnotation.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); RolesAllowed rolesAllowed = (RolesAllowed)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(rolesAllowed); } @RolesAllowed("user") @Path("a") public static class ResourceWithSecurityAnnotation { @GET public void m1() {} } @Test public void ignoresSecurityAnnotationFromClassWhenMethodHasOwn() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithSecurityAnnotationOnClassAndMethod.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); PermitAll permitAll = (PermitAll)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(permitAll); } @RolesAllowed("user") @Path("a") public static class ResourceWithSecurityAnnotationOnClassAndMethod { @PermitAll @GET public void m1() {} } @Test public void inheritsSecurityAnnotationFromMethodOnParentInterface() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithSecurityAnnotationOnMethodInParentInterface.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); RolesAllowed rolesAllowed = (RolesAllowed)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(rolesAllowed); } public interface InterfaceWithSecurityAnnotationOnMethod { @RolesAllowed("user") void m1(); } @Path("a") public static class ResourceWithSecurityAnnotationOnMethodInParentInterface implements InterfaceWithSecurityAnnotationOnMethod { @GET public void m1() {} } @Test public void inheritsSecurityAnnotationFromParentInterface() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithSecurityAnnotationOnParentInterface.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); RolesAllowed rolesAllowed = (RolesAllowed)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(rolesAllowed); } @RolesAllowed("user") public interface InterfaceWithSecurityAnnotation { void m1(); } @Path("a") public static class ResourceWithSecurityAnnotationOnParentInterface implements InterfaceWithSecurityAnnotation { @GET public void m1() {} } @Test public void inheritsSecurityAnnotationFromMethodOnParentClass() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithSecurityAnnotationOnMethodInParentClass.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); RolesAllowed rolesAllowed = (RolesAllowed)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(rolesAllowed); } public static abstract class ClassWithSecurityAnnotationOnMethod { @RolesAllowed("user") public abstract void m1(); } @Path("a") public static class ResourceWithSecurityAnnotationOnMethodInParentClass extends ClassWithSecurityAnnotationOnMethod { @GET public void m1() {} } @Test public void inheritsSecurityAnnotationFromParentClass() { ResourceDescriptor resource = new AbstractResourceDescriptor(ResourceWithSecurityAnnotationOnParentClass.class); List<ResourceMethodDescriptor> resourceMethods = resource.getResourceMethods().get("GET"); assertEquals(1, resourceMethods.get(0).getAnnotations().length); RolesAllowed rolesAllowed = (RolesAllowed)resourceMethods.get(0).getAnnotations()[0]; assertNotNull(rolesAllowed); } @RolesAllowed("user") public static abstract class ClassWithSecurityAnnotation { public abstract void m1(); } @Path("a") public static class ResourceWithSecurityAnnotationOnParentClass extends ClassWithSecurityAnnotation { @GET public void m1() {} } private List<FieldInjector> filterFieldsInsertedByJacocoFrameworkDuringInstrumentation(List<FieldInjector> initialList) { return initialList.stream().filter(fieldInjector -> !fieldInjector.getName().startsWith("$jacocoData")).collect(toList()); } @Test public void processesResourceWithOverriddenMethods() throws Exception { ResourceDescriptor resource = new AbstractResourceDescriptor(Resource2.class); assertEquals(1, resource.getResourceMethods().get("GET").size()); assertEquals(1, resource.getResourceMethods().get("POST").size()); } @Path("/a") public static class Resource1 { @GET public void m1() {} @POST @Consumes("text/plain") public void m2(String s) {} } @Path("/a") public static class Resource2 extends Resource1 { @Override public void m1() {} } }