diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java index 0c3f4d182..aa9878571 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryController.java @@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Jon Brisbin * @author Oliver Gierke */ -@RestController +@RepositoryRestController public class RepositoryController extends AbstractRepositoryRestController { private final Repositories repositories; diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java index 63ffab98b..5384afb77 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryEntityController.java @@ -65,7 +65,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Jon Brisbin * @author Oliver Gierke */ -@RestController +@RepositoryRestController class RepositoryEntityController extends AbstractRepositoryRestController implements ApplicationEventPublisherAware { private static final String BASE_MAPPING = "/{repository}"; diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java index 124d6f1d5..1f33bfb35 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryPropertyReferenceController.java @@ -63,7 +63,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Jon Brisbin * @author Oliver Gierke */ -@RestController +@RepositoryRestController @SuppressWarnings({ "unchecked" }) public class RepositoryPropertyReferenceController extends AbstractRepositoryRestController implements ApplicationEventPublisherAware { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RestController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java similarity index 83% rename from spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RestController.java rename to spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java index 9ba86c5f7..f1ae4cd2b 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RestController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestController.java @@ -24,12 +24,15 @@ import java.lang.annotation.Target; import org.springframework.stereotype.Component; /** + * Annotation to demarcate Spring MVC controllers provided by Spring Data REST. Allows to easily detect them and exclude + * them from standard Spring MVC handling. + * * @author Oliver Gierke */ @Documented @Component @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) -public @interface RestController { +public @interface RepositoryRestController { } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java index ae17361ea..9143fcb22 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerAdapter.java @@ -2,8 +2,9 @@ package org.springframework.data.rest.webmvc; import java.util.List; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.Ordered; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.hateoas.ResourceProcessor; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; @@ -18,26 +19,50 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl */ public class RepositoryRestHandlerAdapter extends ResourceProcessorInvokingHandlerAdapter { - @Autowired private List argumentResolvers; + private final List argumentResolvers; + /** + * Creates a new {@link RepositoryRestHandlerAdapter} using the given {@link HandlerMethodArgumentResolver} and + * {@link ResourceProcessor}s. + * + * @param argumentResolvers must not be {@literal null}. + * @param resourceProcessors must not be {@literal null}. + */ + public RepositoryRestHandlerAdapter(List argumentResolvers, + List> resourceProcessors) { + + super(resourceProcessors); + this.argumentResolvers = argumentResolvers; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.webmvc.ResourceProcessorInvokingHandlerAdapter#afterPropertiesSet() + */ @Override public void afterPropertiesSet() { setCustomArgumentResolvers(argumentResolvers); super.afterPropertiesSet(); } + /* + * (non-Javadoc) + * @see org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#getOrder() + */ @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } + /* + * (non-Javadoc) + * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#supportsInternal(org.springframework.web.method.HandlerMethod) + */ @Override protected boolean supportsInternal(HandlerMethod handlerMethod) { - Class controllerType = handlerMethod.getBeanType(); - return (RepositoryController.class.isAssignableFrom(controllerType) - || RepositoryEntityController.class.isAssignableFrom(controllerType) - || RepositoryPropertyReferenceController.class.isAssignableFrom(controllerType) || RepositorySearchController.class - .isAssignableFrom(controllerType)); - } + Class controllerType = handlerMethod.getBeanType(); + + return AnnotationUtils.findAnnotation(controllerType, RepositoryRestController.class) != null; + } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java index 0564d92bd..9875c3ba5 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java @@ -92,7 +92,7 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping { @Override protected boolean isHandler(Class beanType) { - return AnnotationUtils.findAnnotation(beanType, RestController.class) != null; + return AnnotationUtils.findAnnotation(beanType, RepositoryRestController.class) != null; } @Override diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySchemaController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySchemaController.java index d151512c3..9f7b52fac 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySchemaController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySchemaController.java @@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Jon Brisbin * @author Oliver Gierke */ -@RestController +@RepositoryRestController class RepositorySchemaController { private static final String BASE_MAPPING = "/{repository}"; diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java index a2008d84e..b608d2679 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositorySearchController.java @@ -52,7 +52,7 @@ import org.springframework.web.bind.annotation.ResponseBody; * @author Jon Brisbin * @author Oliver Gierke */ -@RestController +@RepositoryRestController class RepositorySearchController extends AbstractRepositoryRestController { private static final String SEARCH = "/search"; diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceProcessorInvokingHandlerAdapter.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceProcessorInvokingHandlerAdapter.java index 24db81eec..ac40b4698 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceProcessorInvokingHandlerAdapter.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/ResourceProcessorInvokingHandlerAdapter.java @@ -21,11 +21,8 @@ import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.ResourceProcessor; -import org.springframework.http.converter.HttpMessageConverter; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; -import org.springframework.web.bind.support.WebBindingInitializer; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; @@ -47,30 +44,18 @@ public class ResourceProcessorInvokingHandlerAdapter extends RequestMappingHandl private static final Method RETURN_VALUE_HANDLER_METHOD = ReflectionUtils.findMethod( ResourceProcessorInvokingHandlerAdapter.class, "getReturnValueHandlers"); - @Autowired(required = false)// - private List> resourcesProcessors = new ArrayList>(); + private final List> resourcesProcessors; /** - * Empty constructor to setup a {@link ResourceProcessorInvokingHandlerAdapter}. - */ - public ResourceProcessorInvokingHandlerAdapter() { - - } - - /** - * Copy constructor to copy configuration of {@link HttpMessageConverter}s, {@link WebBindingInitializer}, custom - * {@link HandlerMethodArgumentResolver}s and custom {@link HandlerMethodReturnValueHandler}s. + * Creates a new {@link ResourceProcessorInvokingHandlerAdapter} with the given {@link ResourceProcessor}s. * - * @param original must not be {@literal null}. + * @param resourcesProcessors must not be {@literal null}. */ - public ResourceProcessorInvokingHandlerAdapter(RequestMappingHandlerAdapter original) { + @Autowired(required = false) + public ResourceProcessorInvokingHandlerAdapter(List> resourcesProcessors) { - Assert.notNull(original); - - setMessageConverters(original.getMessageConverters()); - setWebBindingInitializer(original.getWebBindingInitializer()); - setCustomArgumentResolvers(original.getCustomArgumentResolvers()); - setCustomReturnValueHandlers(original.getCustomReturnValueHandlers()); + Assert.notNull(resourcesProcessors); + this.resourcesProcessors = resourcesProcessors; } /* diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java index bcacc08b5..2cbc3d812 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.java @@ -17,12 +17,14 @@ package org.springframework.data.rest.webmvc.config; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; @@ -42,11 +44,11 @@ import org.springframework.data.rest.core.support.DomainObjectMerger; import org.springframework.data.rest.core.util.UUIDConverter; import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler; import org.springframework.data.rest.webmvc.PersistentEntityResourceHandlerMethodArgumentResolver; +import org.springframework.data.rest.webmvc.RepositoryRestController; import org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter; import org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping; import org.springframework.data.rest.webmvc.RepositoryRestRequestHandlerMethodArgumentResolver; import org.springframework.data.rest.webmvc.ResourceMetadataHandlerMethodArgumentResolver; -import org.springframework.data.rest.webmvc.RestController; import org.springframework.data.rest.webmvc.ServerHttpRequestMethodArgumentResolver; import org.springframework.data.rest.webmvc.convert.UriListHttpMessageConverter; import org.springframework.data.rest.webmvc.json.Jackson2DatatypeHelper; @@ -59,6 +61,7 @@ import org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguratio import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.hateoas.EntityLinks; import org.springframework.hateoas.RelProvider; +import org.springframework.hateoas.ResourceProcessor; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -83,8 +86,8 @@ import com.fasterxml.jackson.databind.SerializationFeature; * @author Oliver Gierke */ @Configuration -@ComponentScan(basePackageClasses = RestController.class, includeFilters = @Filter(RestController.class), - useDefaultFilters = false) +@ComponentScan(basePackageClasses = RepositoryRestController.class, + includeFilters = @Filter(RepositoryRestController.class), useDefaultFilters = false) @ImportResource("classpath*:META-INF/spring-data-rest/**/*.xml") public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebConfiguration { @@ -94,6 +97,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon RepositoryRestMvcConfiguration.class.getClassLoader()); @Autowired ListableBeanFactory beanFactory; + @Autowired(required = false) List> resourceProcessors = Collections.emptyList(); @Bean public Repositories repositories() { @@ -297,6 +301,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon * Special {@link org.springframework.web.servlet.HandlerAdapter} that only recognizes handler methods defined in the * provided controller classes. * + * @param resourceProcessors {@link ResourceProcessor}s available in the {@link ApplicationContext}. * @return */ @Bean @@ -305,9 +310,9 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon List> messageConverters = defaultMessageConverters(); configureHttpMessageConverters(messageConverters); - RepositoryRestHandlerAdapter handlerAdapter = new RepositoryRestHandlerAdapter(); + RepositoryRestHandlerAdapter handlerAdapter = new RepositoryRestHandlerAdapter(defaultMethodArgumentResolvers(), + resourceProcessors); handlerAdapter.setMessageConverters(messageConverters); - handlerAdapter.setCustomArgumentResolvers(defaultMethodArgumentResolvers()); return handlerAdapter; }