DATACMNS-40 - Back to ResourceProcessors.
Using ResourceProcessors again now as some kind of middle ground between the two former design ideas. We use a value returning callback now to allow manipulating the ResourceSupport instance in its entirety. This enables implementations to be either mutable or immutable. The ResourceProcessor interface is a little less flexible than in the first iteration as we require the same type to be returned.
This commit is contained in:
@@ -16,7 +16,7 @@ dependencies {
|
||||
// Repository Exporter support
|
||||
compile project(":spring-data-rest-repository")
|
||||
|
||||
compile "org.springframework.hateoas:spring-hateoas:0.2.0.BUILD-SNAPSHOT"
|
||||
compile "org.springframework.hateoas:spring-hateoas:0.3.0.BUILD-SNAPSHOT"
|
||||
compile "org.springframework.data:spring-data-commons-core:$sdCommonsVersion"
|
||||
|
||||
runtime "org.hibernate:hibernate-entitymanager:$hibernateVersion"
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
*/
|
||||
public class RepositoryRestHandlerAdapter extends ResourceEnricherInvokingHandlerAdapter {
|
||||
public class RepositoryRestHandlerAdapter extends ResourceProcessorInvokingHandlerAdapter {
|
||||
|
||||
@Autowired
|
||||
private ResourcesReturnValueHandler resourcesReturnValueHandler;
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.rest.webmvc;
|
||||
|
||||
import static org.springframework.data.util.ClassTypeInformation.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -28,64 +29,71 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceEnricher;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* {@link HandlerMethodReturnValueHandler} to post-process the objects returned from controller methods using the
|
||||
* configured {@link ResourceEnricher}s.
|
||||
* configured {@link ResourceProcessor}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
|
||||
public class ResourceProcessorHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
|
||||
|
||||
private static final TypeInformation<?> RESOURCE_TYPE = from(Resource.class);
|
||||
private static final TypeInformation<?> RESOURCES_TYPE = from(Resources.class);
|
||||
private static final Field CONTENT_FIELD = ReflectionUtils.findField(Resources.class, "content");
|
||||
|
||||
static {
|
||||
ReflectionUtils.makeAccessible(CONTENT_FIELD);
|
||||
}
|
||||
|
||||
private final HandlerMethodReturnValueHandler delegate;
|
||||
private final List<EnricherWrapper> enrichers;
|
||||
private final List<ProcessorWrapper> processors;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResourceEnricherHandlerMethodReturnValueHandler} using the given delegate to eventually
|
||||
* Creates a new {@link ResourceProcessorHandlerMethodReturnValueHandler} using the given delegate to eventually
|
||||
* delegate calls to {@link #handleReturnValue(Object, MethodParameter, ModelAndViewContainer, NativeWebRequest)} to.
|
||||
* Will consider the given {@link ResourceEnricher} to post-process the controller methods return value to before
|
||||
* Will consider the given {@link ResourceProcessor} to post-process the controller methods return value to before
|
||||
* invoking the delegate.
|
||||
*
|
||||
* @param delegate the {@link HandlerMethodReturnValueHandler} to evenually delegate calls to, must not be
|
||||
* {@literal null}.
|
||||
* @param enrichers the {@link ResourceEnricher}s to be considered, must not be {@literal null}.
|
||||
* @param processors the {@link ResourceProcessor}s to be considered, must not be {@literal null}.
|
||||
*/
|
||||
public ResourceEnricherHandlerMethodReturnValueHandler(HandlerMethodReturnValueHandler delegate,
|
||||
List<ResourceEnricher<?>> enrichers) {
|
||||
public ResourceProcessorHandlerMethodReturnValueHandler(HandlerMethodReturnValueHandler delegate,
|
||||
List<ResourceProcessor<?>> processors) {
|
||||
|
||||
Assert.notNull(delegate, "Delegate must not be null!");
|
||||
Assert.notNull(enrichers, "ResourceEnrichers must not be null!");
|
||||
Assert.notNull(processors, "ResourceProcessors must not be null!");
|
||||
|
||||
this.delegate = delegate;
|
||||
this.enrichers = new ArrayList<EnricherWrapper>();
|
||||
this.processors = new ArrayList<ProcessorWrapper>();
|
||||
|
||||
for (ResourceEnricher<?> enricher : enrichers) {
|
||||
for (ResourceProcessor<?> processor : processors) {
|
||||
|
||||
TypeInformation<?> componentType = from(enricher.getClass()).getSuperTypeInformation(ResourceEnricher.class)
|
||||
TypeInformation<?> componentType = from(processor.getClass()).getSuperTypeInformation(ResourceProcessor.class)
|
||||
.getComponentType();
|
||||
Class<?> rawType = componentType.getType();
|
||||
|
||||
if (Resource.class.isAssignableFrom(rawType)) {
|
||||
this.enrichers.add(new ResourceEnricherWrapper(enricher));
|
||||
this.processors.add(new ResourceProcessorWrapper(processor));
|
||||
} else if (Resources.class.isAssignableFrom(rawType)) {
|
||||
this.enrichers.add(new ResourcesEnricherWrapper(enricher));
|
||||
this.processors.add(new ResourcesProcessorWrapper(processor));
|
||||
} else {
|
||||
this.enrichers.add(new DefaultEnricherWrapper(enricher));
|
||||
this.processors.add(new DefaultProcessorWrapper(processor));
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(this.enrichers, AnnotationAwareOrderComparator.INSTANCE);
|
||||
Collections.sort(this.processors, AnnotationAwareOrderComparator.INSTANCE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -117,7 +125,7 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
return;
|
||||
}
|
||||
|
||||
// We have a Resource or Resources - find suitable enrichers
|
||||
// We have a Resource or Resources - find suitable processors
|
||||
TypeInformation<?> targetType = ClassTypeInformation.fromReturnTypeOf(returnType.getMethod());
|
||||
|
||||
// Unbox HttpEntity
|
||||
@@ -136,6 +144,7 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
|
||||
Resources<?> resources = (Resources<?>) value;
|
||||
TypeInformation<?> elementTargetType = targetType.getSuperTypeInformation(Resources.class).getComponentType();
|
||||
List<Object> result = new ArrayList<Object>(resources.getContent().size());
|
||||
|
||||
for (Object element : resources) {
|
||||
|
||||
@@ -144,22 +153,59 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
elementTargetType = elementTypeInformation;
|
||||
}
|
||||
|
||||
for (EnricherWrapper wrapper : this.enrichers) {
|
||||
if (wrapper.supports(elementTargetType, element)) {
|
||||
wrapper.invokeEnricher(element);
|
||||
}
|
||||
}
|
||||
result.add(invokeProcessorsFor(element, elementTargetType));
|
||||
}
|
||||
|
||||
ReflectionUtils.setField(CONTENT_FIELD, resources, result);
|
||||
}
|
||||
|
||||
Object result = invokeProcessorsFor(value, targetType);
|
||||
delegate.handleReturnValue(rewrapResult(result, returnValue), returnType, mavContainer, webRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes all registered {@link ResourceProcessor}s registered for the given {@link TypeInformation}.
|
||||
*
|
||||
* @param value the object to process
|
||||
* @param targetType
|
||||
* @return
|
||||
*/
|
||||
private Object invokeProcessorsFor(Object value, TypeInformation<?> targetType) {
|
||||
|
||||
Object currentValue = value;
|
||||
|
||||
// Process actual value
|
||||
for (EnricherWrapper wrapper : this.enrichers) {
|
||||
if (wrapper.supports(targetType, value)) {
|
||||
wrapper.invokeEnricher(value);
|
||||
for (ProcessorWrapper wrapper : this.processors) {
|
||||
if (wrapper.supports(targetType, currentValue)) {
|
||||
currentValue = wrapper.invokeProcessor(currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-wraps the result of the post-processing work into an {@link HttpEntity} or {@link ResponseEntity} if the
|
||||
* original value was one of those two types. Copies headers and status code from the original value but uses the new
|
||||
* body.
|
||||
*
|
||||
* @param newBody the post-processed value.
|
||||
* @param originalValue the original input value.
|
||||
* @return
|
||||
*/
|
||||
static Object rewrapResult(Object newBody, Object originalValue) {
|
||||
|
||||
if (!(originalValue instanceof HttpEntity)) {
|
||||
return newBody;
|
||||
}
|
||||
|
||||
if (originalValue instanceof ResponseEntity) {
|
||||
ResponseEntity<?> source = (ResponseEntity<?>) originalValue;
|
||||
return new ResponseEntity<Object>(newBody, source.getHeaders(), source.getStatusCode());
|
||||
} else {
|
||||
HttpEntity<?> source = (HttpEntity<?>) originalValue;
|
||||
return new HttpEntity<Object>(newBody, source.getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,58 +219,58 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to unify interaction with {@link ResourceEnricher}s. The {@link Ordered} rank should be determined by the
|
||||
* underlying processor.
|
||||
* Interface to unify interaction with {@link ResourceProcessor}s. The {@link Ordered} rank should be determined by
|
||||
* the underlying processor.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private interface EnricherWrapper extends Ordered {
|
||||
private interface ProcessorWrapper extends Ordered {
|
||||
|
||||
/**
|
||||
* Returns whether the underlying processor supports the given {@link TypeInformation}. It might also aditionally
|
||||
* inspect the object that would eventually be handed to the enricher.
|
||||
* inspect the object that would eventually be handed to the processor.
|
||||
*
|
||||
* @param typeInformation the type of object to be post processed, will never be {@literal null}.
|
||||
* @param value the object that would be passed into the enricher eventually, can be {@literal null}.
|
||||
* @param value the object that would be passed into the processor eventually, can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
boolean supports(TypeInformation<?> typeInformation, Object value);
|
||||
|
||||
/**
|
||||
* Performs the actual invocation of the enricher. Implementations can be sure
|
||||
* Performs the actual invocation of the processor. Implementations can be sure
|
||||
* {@link #supports(TypeInformation, Object)} has been called before and returned {@literal true}.
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
void invokeEnricher(Object object);
|
||||
Object invokeProcessor(Object object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of {@link EnricherWrapper} to generically deal with {@link ResourceSupport} types.
|
||||
* Default implementation of {@link ProcessorWrapper} to generically deal with {@link ResourceSupport} types.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class DefaultEnricherWrapper implements EnricherWrapper {
|
||||
private static class DefaultProcessorWrapper implements ProcessorWrapper {
|
||||
|
||||
private final ResourceEnricher<?> enricher;
|
||||
private final ResourceProcessor<?> processor;
|
||||
private final TypeInformation<?> targetType;
|
||||
|
||||
/**
|
||||
* Creates a ne {@link DefaultEnricherWrapper} with the given {@link ResourceEnricher}.
|
||||
* Creates a ne {@link DefaultProcessorWrapper} with the given {@link ResourceProcessor}.
|
||||
*
|
||||
* @param enricher must not be {@literal null}.
|
||||
* @param processor must not be {@literal null}.
|
||||
*/
|
||||
public DefaultEnricherWrapper(ResourceEnricher<?> enricher) {
|
||||
public DefaultProcessorWrapper(ResourceProcessor<?> processor) {
|
||||
|
||||
Assert.notNull(enricher);
|
||||
Assert.notNull(processor);
|
||||
|
||||
this.enricher = enricher;
|
||||
this.targetType = from(enricher.getClass()).getSuperTypeInformation(ResourceEnricher.class).getComponentType();
|
||||
this.processor = processor;
|
||||
this.targetType = from(processor.getClass()).getSuperTypeInformation(ResourceProcessor.class).getComponentType();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceEnricherHandlerMethodReturnValueHandler.PostProcessorWrapper#supports(org.springframework.data.util.TypeInformation, java.lang.Object)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceProcessorHandlerMethodReturnValueHandler.PostProcessorWrapper#supports(org.springframework.data.util.TypeInformation, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(TypeInformation<?> typeInformation, Object value) {
|
||||
@@ -233,12 +279,12 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceEnricherHandlerMethodReturnValueHandler.PostProcessorWrapper#invokeProcessor(java.lang.Object)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceProcessorHandlerMethodReturnValueHandler.PostProcessorWrapper#invokeProcessor(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void invokeEnricher(Object object) {
|
||||
((ResourceEnricher<ResourceSupport>) enricher).enrich((ResourceSupport) object);
|
||||
public Object invokeProcessor(Object object) {
|
||||
return ((ResourceProcessor<ResourceSupport>) processor).enrich((ResourceSupport) object);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -247,11 +293,11 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return CustomOrderAwareComparator.INSTANCE.getOrder(enricher);
|
||||
return CustomOrderAwareComparator.INSTANCE.getOrder(processor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target type the underlying {@link ResourceEnricher} wants to get invoked for.
|
||||
* Returns the target type the underlying {@link ResourceProcessor} wants to get invoked for.
|
||||
*
|
||||
* @return the targetType
|
||||
*/
|
||||
@@ -261,25 +307,25 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EnricherWrapper} to deal with {@link ResourceEnricher}s for {@link Resource}s. Will fall back to peeking
|
||||
* {@link ProcessorWrapper} to deal with {@link ResourceProcessor}s for {@link Resource}s. Will fall back to peeking
|
||||
* into the {@link Resource}'s content for type resolution.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class ResourceEnricherWrapper extends DefaultEnricherWrapper {
|
||||
private static class ResourceProcessorWrapper extends DefaultProcessorWrapper {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResourceEnricherWrapper} for the given {@link ResourceEnricher}.
|
||||
* Creates a new {@link ResourceProcessorWrapper} for the given {@link ResourceProcessor}.
|
||||
*
|
||||
* @param processor must not be {@literal null}.
|
||||
*/
|
||||
public ResourceEnricherWrapper(ResourceEnricher<?> processor) {
|
||||
public ResourceProcessorWrapper(ResourceProcessor<?> processor) {
|
||||
super(processor);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceEnricherHandlerMethodReturnValueHandler.PostProcessorWrapper#supports(org.springframework.data.util.TypeInformation, java.lang.Object)
|
||||
* @see org.springframework.data.rest.webmvc.ResourceProcessorHandlerMethodReturnValueHandler.PostProcessorWrapper#supports(org.springframework.data.util.TypeInformation, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(TypeInformation<?> typeInformation, Object value) {
|
||||
@@ -317,20 +363,20 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EnricherWrapper} for {@link ResourceEnricher}s targeting {@link Resources}. Will peek into the content of
|
||||
* {@link ProcessorWrapper} for {@link ResourceProcessor}s targeting {@link Resources}. Will peek into the content of
|
||||
* the {@link Resources} for type matching decisions if needed.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class ResourcesEnricherWrapper extends DefaultEnricherWrapper {
|
||||
private static class ResourcesProcessorWrapper extends DefaultProcessorWrapper {
|
||||
|
||||
/**
|
||||
* Creates a new {@link ResourcesEnricherWrapper} for the given {@link ResourceEnricher}.
|
||||
* Creates a new {@link ResourcesProcessorWrapper} for the given {@link ResourceProcessor}.
|
||||
*
|
||||
* @param enricher must not be {@literal null}.
|
||||
* @param processor must not be {@literal null}.
|
||||
*/
|
||||
public ResourcesEnricherWrapper(ResourceEnricher<?> enricher) {
|
||||
super(enricher);
|
||||
public ResourcesProcessorWrapper(ResourceProcessor<?> processor) {
|
||||
super(processor);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -374,7 +420,7 @@ public class ResourceEnricherHandlerMethodReturnValueHandler implements HandlerM
|
||||
}
|
||||
|
||||
TypeInformation<?> resourceTypeInformation = target.getSuperTypeInformation(Resources.class).getComponentType();
|
||||
return ResourceEnricherWrapper.isValueTypeMatch((Resource<?>) element, resourceTypeInformation);
|
||||
return ResourceProcessorWrapper.isValueTypeMatch((Resource<?>) element, resourceTypeInformation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.hateoas.ResourceEnricher;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
@@ -30,7 +30,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||
|
||||
/**
|
||||
* Special {@link RequestMappingHandlerAdapter} that tweaks the {@link HandlerMethodReturnValueHandlerComposite} to be
|
||||
* proxied by a {@link ResourceEnricherHandlerMethodReturnValueHandler} which will invoke the {@link ResourceEnricher}s
|
||||
* proxied by a {@link ResourceProcessorHandlerMethodReturnValueHandler} which will invoke the {@link ResourceProcessor}s
|
||||
* found in the application context and eventually delegate to the originally configured
|
||||
* {@link HandlerMethodReturnValueHandler}.
|
||||
* <p>
|
||||
@@ -39,15 +39,15 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ResourceEnricherInvokingHandlerAdapter extends RequestMappingHandlerAdapter {
|
||||
public class ResourceProcessorInvokingHandlerAdapter extends RequestMappingHandlerAdapter {
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<ResourceEnricher<?>> resourcesEnrichers = new ArrayList<ResourceEnricher<?>>();
|
||||
private List<ResourceProcessor<?>> resourcesProcessors = new ArrayList<ResourceProcessor<?>>();
|
||||
|
||||
/**
|
||||
* Empty constructor to setup a {@link ResourceEnricherInvokingHandlerAdapter}.
|
||||
* Empty constructor to setup a {@link ResourceProcessorInvokingHandlerAdapter}.
|
||||
*/
|
||||
public ResourceEnricherInvokingHandlerAdapter() {
|
||||
public ResourceProcessorInvokingHandlerAdapter() {
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class ResourceEnricherInvokingHandlerAdapter extends RequestMappingHandle
|
||||
*
|
||||
* @param original must not be {@literal null}.
|
||||
*/
|
||||
public ResourceEnricherInvokingHandlerAdapter(RequestMappingHandlerAdapter original) {
|
||||
public ResourceProcessorInvokingHandlerAdapter(RequestMappingHandlerAdapter original) {
|
||||
|
||||
Assert.notNull(original);
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ResourceEnricherInvokingHandlerAdapter extends RequestMappingHandle
|
||||
|
||||
// Set up ResourceProcessingHandlerMethodResolver to delegate to originally configured ones
|
||||
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
newHandlers.add(new ResourceEnricherHandlerMethodReturnValueHandler(oldHandlers, resourcesEnrichers));
|
||||
newHandlers.add(new ResourceProcessorHandlerMethodReturnValueHandler(oldHandlers, resourcesProcessors));
|
||||
|
||||
// Configure the new handler to be used
|
||||
this.setReturnValueHandlers(newHandlers);
|
||||
@@ -33,10 +33,9 @@ import org.mockito.Mockito;
|
||||
import org.mockito.internal.matchers.Equals;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.rest.webmvc.ResourceEnricherHandlerMethodReturnValueHandler;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.data.rest.webmvc.ResourceProcessorHandlerMethodReturnValueHandler;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceEnricher;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -46,12 +45,12 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ResourceEnricherHandlerMethodReturnValueHandler}.
|
||||
* Unit tests for {@link ResourceProcessorHandlerMethodReturnValueHandler}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTests {
|
||||
|
||||
@Mock
|
||||
HandlerMethodReturnValueHandler delegate;
|
||||
@@ -59,20 +58,14 @@ public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
@Mock
|
||||
MethodParameter parameter;
|
||||
|
||||
List<ResourceEnricher<?>> resourceEnrichers;
|
||||
List<ResourceProcessor<?>> resourceProcessors;
|
||||
|
||||
Resource<String> source;
|
||||
Resource<String> result;
|
||||
Resource<String> source = new Resource<String>("foo");
|
||||
Resource<String> result = StringResourceProcessor.RESULT;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
resourceEnrichers = new ArrayList<ResourceEnricher<?>>();
|
||||
resetResources();
|
||||
}
|
||||
|
||||
private void resetResources() {
|
||||
source = new Resource<String>("foo");
|
||||
result = new Resource<String>("foo", StringResourceEnricher.LINK);
|
||||
resourceProcessors = new ArrayList<ResourceProcessor<?>>();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -88,8 +81,8 @@ public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
private void assertSupport(boolean value) {
|
||||
|
||||
when(delegate.supportsReturnType(Mockito.any(MethodParameter.class))).thenReturn(value);
|
||||
HandlerMethodReturnValueHandler handler = new ResourceEnricherHandlerMethodReturnValueHandler(delegate,
|
||||
resourceEnrichers);
|
||||
HandlerMethodReturnValueHandler handler = new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
|
||||
resourceProcessors);
|
||||
|
||||
assertThat(handler.supportsReturnType(parameter), is(value));
|
||||
}
|
||||
@@ -97,81 +90,65 @@ public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
@Test
|
||||
public void invokesStringPostProcessorForSimpleStringResource() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new StringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceProcessors.add(new StringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
|
||||
HttpEntity<Resource<String>> input = new HttpEntity<Resource<String>>(source);
|
||||
HttpEntity<Resource<String>> output = new HttpEntity<Resource<String>>(result);
|
||||
|
||||
assertProcessorInvokedForMethod("stringResourceEntity", input, output);
|
||||
resetResources();
|
||||
input = new HttpEntity<Resource<String>>(source);
|
||||
assertProcessorInvokedForMethod("resourceEntity", input, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokesStringPostProcessorForSimpleStringResourceInResponseEntity() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new StringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceProcessors.add(new StringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
|
||||
ResponseEntity<Resource<String>> input = new ResponseEntity<Resource<String>>(source, HttpStatus.OK);
|
||||
ResponseEntity<Resource<String>> output = new ResponseEntity<Resource<String>>(result, HttpStatus.OK);
|
||||
|
||||
assertProcessorInvokedForMethod("stringResourceEntity", input, output);
|
||||
|
||||
resetResources();
|
||||
input = new ResponseEntity<Resource<String>>(source, HttpStatus.OK);
|
||||
assertProcessorInvokedForMethod("resourceEntity", input, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokesStringPostProcessorForSimpleStringResources() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new StringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceEnrichers.add(new StringResourcesEnricher());
|
||||
resourceProcessors.add(new StringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
resourceProcessors.add(new StringResourcesProcessor());
|
||||
|
||||
Resources<Resource<String>> sources = new Resources<Resource<String>>(Collections.singleton(source));
|
||||
|
||||
|
||||
HttpEntity<Resources<Resource<String>>> input = new HttpEntity<Resources<Resource<String>>>(sources);
|
||||
HttpEntity<Resources<Resource<String>>> output = new HttpEntity<Resources<Resource<String>>>(
|
||||
new Resources<Resource<String>>(Collections.singleton(result), StringResourcesEnricher.LINK));
|
||||
StringResourcesProcessor.RESULT);
|
||||
|
||||
assertProcessorInvokedForMethod("stringResourceEntity", input, output);
|
||||
|
||||
resetResources();
|
||||
input = new HttpEntity<Resources<Resource<String>>>(new Resources<Resource<String>>(Collections.singleton(source)));
|
||||
output = new HttpEntity<Resources<Resource<String>>>(
|
||||
new Resources<Resource<String>>(Collections.singleton(result), StringResourcesEnricher.LINK));
|
||||
assertProcessorInvokedForMethod("resourceEntity", input, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invokesStringPostProcessorForSpecializedStringResource() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new StringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceProcessors.add(new StringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
|
||||
HttpEntity<Resource<String>> stringOutput = new HttpEntity<Resource<String>>(result);
|
||||
HttpEntity<StringResource> specializedInput = new HttpEntity<StringResource>(new StringResource("foo"));
|
||||
HttpEntity<StringResource> stringOutput = new HttpEntity<StringResource>(new StringResource("foo",
|
||||
StringResourceEnricher.LINK));
|
||||
|
||||
assertProcessorInvokedForMethod("stringResourceEntity", specializedInput, stringOutput);
|
||||
|
||||
specializedInput = new HttpEntity<StringResource>(new StringResource("foo"));
|
||||
assertProcessorInvokedForMethod("resourceEntity", specializedInput, stringOutput);
|
||||
|
||||
specializedInput = new HttpEntity<StringResource>(new StringResource("foo"));
|
||||
assertProcessorInvokedForMethod("specializedStringResourceEntity", specializedInput, stringOutput);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotInvokeSpecializedStringPostProcessorForSimpleStringResource() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new SpecializedStringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceProcessors.add(new SpecializedStringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
|
||||
HttpEntity<Resource<String>> input = new HttpEntity<Resource<String>>(source);
|
||||
|
||||
@@ -181,12 +158,11 @@ public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
@Test
|
||||
public void invokesSpecializedStringPostProcessor() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new SpecializedStringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceProcessors.add(new SpecializedStringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
|
||||
HttpEntity<StringResource> input = new HttpEntity<StringResource>(new StringResource("foo"));
|
||||
HttpEntity<StringResource> output = new HttpEntity<StringResource>(new StringResource("foo",
|
||||
SpecializedStringResourceEnricher.LINK));
|
||||
HttpEntity<StringResource> output = new HttpEntity<StringResource>(SpecializedStringResourceProcessor.RESULT);
|
||||
|
||||
assertProcessorInvokedForMethod("specializedStringResourceEntity", input, output);
|
||||
}
|
||||
@@ -194,23 +170,22 @@ public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
@Test
|
||||
public void invokesLongPostProcessorForLongResource() throws Exception {
|
||||
|
||||
resourceEnrichers.add(new StringResourceEnricher());
|
||||
resourceEnrichers.add(new LongResourceEnricher());
|
||||
resourceProcessors.add(new StringResourceProcessor());
|
||||
resourceProcessors.add(new LongResourceProcessor());
|
||||
|
||||
HttpEntity<Resource<Long>> input = new HttpEntity<Resource<Long>>(new Resource<Long>(50L));
|
||||
HttpEntity<LongResource> specializedInput = new HttpEntity<LongResource>(new LongResource(50L));
|
||||
HttpEntity<Resource<Long>> output = new HttpEntity<Resource<Long>>(LongResourceProcessor.RESULT);
|
||||
|
||||
assertProcessorInvokedForMethod("resourceEntity", specializedInput, new HttpEntity<LongResource>(new LongResource(
|
||||
50L, LongResourceEnricher.LINK)));
|
||||
assertProcessorInvokedForMethod("numberResourceEntity", input, new HttpEntity<Resource<Long>>(new Resource<Long>(
|
||||
50L, LongResourceEnricher.LINK)));
|
||||
assertProcessorInvokedForMethod("resourceEntity", specializedInput, output);
|
||||
assertProcessorInvokedForMethod("numberResourceEntity", input, output);
|
||||
}
|
||||
|
||||
private void assertProcessorInvokedForMethod(String methodName, Object returnValue, Object processedValue)
|
||||
throws Exception {
|
||||
|
||||
HandlerMethodReturnValueHandler handler = new ResourceEnricherHandlerMethodReturnValueHandler(delegate,
|
||||
resourceEnrichers);
|
||||
HandlerMethodReturnValueHandler handler = new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
|
||||
resourceProcessors);
|
||||
|
||||
Method method = Controller.class.getMethod(methodName);
|
||||
MethodParameter returnType = new MethodParameter(method, -1);
|
||||
@@ -292,58 +267,69 @@ public class ResourceEnricherHandlerMethodReturnValueHandlerUnitTests {
|
||||
|
||||
ResponseEntity<Resources<?>> resourcesResponseEntity();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link ResourceProcessor} to process {@link String}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class StringResourceProcessor implements ResourceProcessor<Resource<String>> {
|
||||
|
||||
static final Resource<String> RESULT = new Resource<String>("bar");
|
||||
|
||||
@Override
|
||||
public Resource<String> enrich(Resource<String> resource) {
|
||||
return RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
static class StringResourcesProcessor implements ResourceProcessor<Resources<Resource<String>>> {
|
||||
|
||||
static final Resources<Resource<String>> RESULT = new Resources<Resource<String>>(
|
||||
Collections.singleton(StringResourceProcessor.RESULT));
|
||||
|
||||
@Override
|
||||
public Resources<Resource<String>> enrich(Resources<Resource<String>> resources) {
|
||||
return RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ResourceProcessor} to process {@link Long} values.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
static class LongResourceProcessor implements ResourceProcessor<Resource<Long>> {
|
||||
|
||||
static final Resource<Long> RESULT = new Resource<Long>(10L);
|
||||
|
||||
@Override
|
||||
public Resource<Long> enrich(Resource<Long> resource) {
|
||||
return RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
static class StringResource extends Resource<String> {
|
||||
|
||||
public StringResource(String value, Link... links) {
|
||||
super(value, links);
|
||||
public StringResource(String value) {
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
||||
static class LongResource extends Resource<Long> {
|
||||
|
||||
public LongResource(Long value, Link... links) {
|
||||
super(value, links);
|
||||
public LongResource(Long value) {
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
||||
static class StringResourceEnricher implements ResourceEnricher<Resource<String>> {
|
||||
static class SpecializedStringResourceProcessor implements ResourceProcessor<StringResource> {
|
||||
|
||||
static final Link LINK = new Link("string-resource");
|
||||
static final StringResource RESULT = new StringResource("foobar");
|
||||
|
||||
@Override
|
||||
public void enrich(Resource<String> resource) {
|
||||
resource.add(LINK);
|
||||
}
|
||||
}
|
||||
|
||||
static class StringResourcesEnricher implements ResourceEnricher<Resources<Resource<String>>> {
|
||||
|
||||
static final Link LINK = new Link("string-resources");
|
||||
|
||||
@Override
|
||||
public void enrich(Resources<Resource<String>> resource) {
|
||||
resource.add(LINK);
|
||||
}
|
||||
}
|
||||
|
||||
static class LongResourceEnricher implements ResourceEnricher<Resource<Long>> {
|
||||
|
||||
static final Link LINK = new Link("long-resource");
|
||||
|
||||
@Override
|
||||
public void enrich(Resource<Long> resource) {
|
||||
resource.add(LINK);
|
||||
}
|
||||
}
|
||||
|
||||
static class SpecializedStringResourceEnricher implements ResourceEnricher<StringResource> {
|
||||
|
||||
static final Link LINK = new Link("specialized-string");
|
||||
|
||||
@Override
|
||||
public void enrich(StringResource resource) {
|
||||
resource.add(LINK);
|
||||
public StringResource enrich(StringResource resource) {
|
||||
return RESULT;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user