DATAREST-479 - Empty collections now render a dedicated _embedded property.
Instead of rendering an empty _embedded document for empty collections and pages we now explicitly trigger the creations of an EmbeddedWrapper for that empty, collection to preserve the collection's element type. Tweaked ResourceProcessorHandlerMethodReturnValueHandler to invoke ResourceProcessor instances for those empty collections, too. PRHMRVH now checks the assignability of the raw resource type before analyzing the value type for a match. RepositorySearchController now adds additional self links for the list of searches and a search execution.
This commit is contained in:
@@ -50,7 +50,7 @@ public interface MethodResourceMapping extends ResourceMapping {
|
||||
|
||||
/**
|
||||
* Returns the domain type that the query method returns. This will inspect wrapper types ({@link Collection}s,
|
||||
* {@link Map}s, {@link Optional}s etc.) for their elemtn or value types.
|
||||
* {@link Map}s, {@link Optional}s etc.) for their element or value types.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
* @since 2.3
|
||||
|
||||
@@ -111,7 +111,28 @@ public class SearchResourceMappings implements Iterable<MethodResourceMapping>,
|
||||
|
||||
for (MethodResourceMapping mapping : this) {
|
||||
|
||||
if (mapping.isExported() && mapping.getRel().endsWith(rel)) {
|
||||
if (mapping.isExported() && mapping.getRel().equals(rel)) {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MethodResourceMapping} for the given path.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 2.4
|
||||
*/
|
||||
public MethodResourceMapping getExportedMethodMappingForPath(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be null or empty!");
|
||||
|
||||
for (MethodResourceMapping mapping : this) {
|
||||
|
||||
if (mapping.isExported() && mapping.getPath().matches(path)) {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.data.rest.webmvc;
|
||||
import static org.springframework.data.rest.webmvc.ControllerUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
@@ -32,9 +33,11 @@ import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.hateoas.core.EmbeddedWrappers;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* @author Jon Brisbin
|
||||
@@ -44,6 +47,8 @@ import org.springframework.util.ClassUtils;
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
class AbstractRepositoryRestController {
|
||||
|
||||
private static final EmbeddedWrappers WRAPPERS = new EmbeddedWrappers(false);
|
||||
|
||||
private final PagedResourcesAssembler<Object> pagedResourcesAssembler;
|
||||
private final AuditableBeanWrapperFactory auditableBeanWrapperFactory;
|
||||
|
||||
@@ -75,13 +80,14 @@ class AbstractRepositoryRestController {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected Resources<?> toResources(Iterable<?> source, PersistentEntityResourceAssembler assembler, Link baseLink) {
|
||||
protected Resources<?> toResources(Iterable<?> source, PersistentEntityResourceAssembler assembler,
|
||||
Class<?> domainType, Link baseLink) {
|
||||
|
||||
if (source instanceof Page) {
|
||||
Page<Object> page = (Page<Object>) source;
|
||||
return entitiesToResources(page, assembler, baseLink);
|
||||
return entitiesToResources(page, assembler, domainType, baseLink);
|
||||
} else if (source instanceof Iterable) {
|
||||
return entitiesToResources((Iterable<Object>) source, assembler);
|
||||
return entitiesToResources((Iterable<Object>) source, assembler, domainType);
|
||||
} else {
|
||||
return new Resources(EMPTY_RESOURCE_LIST);
|
||||
}
|
||||
@@ -93,13 +99,15 @@ class AbstractRepositoryRestController {
|
||||
*
|
||||
* @param source can be must not be {@literal null}.
|
||||
* @param assembler must not be {@literal null}.
|
||||
* @param domainType the domain type in case the source is an empty iterable, must not be {@literal null}.
|
||||
* @param baseLink can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Object toResource(Object source, PersistentEntityResourceAssembler assembler, Link baseLink) {
|
||||
protected Object toResource(Object source, PersistentEntityResourceAssembler assembler, Class<?> domainType,
|
||||
Link baseLink) {
|
||||
|
||||
if (source instanceof Iterable) {
|
||||
return toResources((Iterable<?>) source, assembler, baseLink);
|
||||
return toResources((Iterable<?>) source, assembler, domainType, baseLink);
|
||||
} else if (source == null) {
|
||||
throw new ResourceNotFoundException();
|
||||
} else if (ClassUtils.isPrimitiveOrWrapper(source.getClass())) {
|
||||
@@ -109,14 +117,25 @@ class AbstractRepositoryRestController {
|
||||
return assembler.toFullResource(source);
|
||||
}
|
||||
|
||||
protected Resources<? extends Resource<Object>> entitiesToResources(Page<Object> page,
|
||||
PersistentEntityResourceAssembler assembler, Link baseLink) {
|
||||
protected Resources<?> entitiesToResources(Page<Object> page, PersistentEntityResourceAssembler assembler,
|
||||
Class<?> domainType, Link baseLink) {
|
||||
|
||||
if (page.getContent().isEmpty()) {
|
||||
return pagedResourcesAssembler.toEmptyResource(page, domainType, baseLink);
|
||||
}
|
||||
|
||||
return baseLink == null ? pagedResourcesAssembler.toResource(page, assembler) : pagedResourcesAssembler.toResource(
|
||||
page, assembler, baseLink);
|
||||
}
|
||||
|
||||
protected Resources<Resource<Object>> entitiesToResources(Iterable<Object> entities,
|
||||
PersistentEntityResourceAssembler assembler) {
|
||||
protected Resources<?> entitiesToResources(Iterable<Object> entities, PersistentEntityResourceAssembler assembler,
|
||||
Class<?> domainType) {
|
||||
|
||||
if (!entities.iterator().hasNext()) {
|
||||
|
||||
List<Object> content = Arrays.<Object> asList(WRAPPERS.emptyCollectionOf(domainType));
|
||||
return new Resources<Object>(content, getDefaultSelfLink());
|
||||
}
|
||||
|
||||
List<Resource<Object>> resources = new ArrayList<Resource<Object>>();
|
||||
|
||||
@@ -124,7 +143,7 @@ class AbstractRepositoryRestController {
|
||||
resources.add(obj == null ? null : assembler.toResource(obj));
|
||||
}
|
||||
|
||||
return new Resources<Resource<Object>>(resources);
|
||||
return new Resources<Resource<Object>>(resources, getDefaultSelfLink());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,4 +195,8 @@ class AbstractRepositoryRestController {
|
||||
protected AuditableBeanWrapper getAuditableBeanWrapper(Object source) {
|
||||
return auditableBeanWrapperFactory.getBeanWrapperFor(source);
|
||||
}
|
||||
|
||||
protected Link getDefaultSelfLink() {
|
||||
return new Link(ServletUriComponentsBuilder.fromCurrentRequest().build().toUriString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,9 +170,9 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
*/
|
||||
@ResponseBody
|
||||
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET)
|
||||
public Resources<?> getCollectionResource(final RootResourceInformation resourceInformation,
|
||||
DefaultedPageable pageable, Sort sort, PersistentEntityResourceAssembler assembler)
|
||||
throws ResourceNotFoundException, HttpRequestMethodNotSupportedException {
|
||||
public Resources<?> getCollectionResource(RootResourceInformation resourceInformation, DefaultedPageable pageable,
|
||||
Sort sort, PersistentEntityResourceAssembler assembler) throws ResourceNotFoundException,
|
||||
HttpRequestMethodNotSupportedException {
|
||||
|
||||
resourceInformation.verifySupportedMethod(HttpMethod.GET, ResourceType.COLLECTION);
|
||||
|
||||
@@ -202,7 +202,7 @@ class RepositoryEntityController extends AbstractRepositoryRestController implem
|
||||
Link baseLink = entityLinks.linkToPagedResource(resourceInformation.getDomainType(), pageable.isDefault() ? null
|
||||
: pageable.getPageable());
|
||||
|
||||
Resources<?> result = toResources(results, assembler, baseLink);
|
||||
Resources<?> result = toResources(results, assembler, metadata.getDomainType(), baseLink);
|
||||
result.add(links);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed 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.springframework.data.rest.webmvc;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
|
||||
/**
|
||||
* Dedicated resource type to represent the links pointing to collection resources exposed for repositories.
|
||||
*
|
||||
* @author Jon Brisbin
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryLinksResource extends Resources<Object> {
|
||||
|
||||
public RepositoryLinksResource() {
|
||||
super(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
public class RepositoryLinksResource extends ResourceSupport {}
|
||||
|
||||
@@ -107,7 +107,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
@RequestMapping(value = BASE_MAPPING, method = RequestMethod.GET)
|
||||
public ResponseEntity<ResourceSupport> followPropertyReference(final RootResourceInformation repoRequest,
|
||||
@BackendId Serializable id, @PathVariable String property, final PersistentEntityResourceAssembler assembler)
|
||||
@BackendId Serializable id, final @PathVariable String property, final PersistentEntityResourceAssembler assembler)
|
||||
throws Exception {
|
||||
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
@@ -123,13 +123,7 @@ class RepositoryPropertyReferenceController extends AbstractRepositoryRestContro
|
||||
|
||||
if (prop.property.isCollectionLike()) {
|
||||
|
||||
List<Resource<?>> resources = new ArrayList<Resource<?>>();
|
||||
|
||||
for (Object obj : (Iterable<Object>) prop.propertyValue) {
|
||||
resources.add(assembler.toResource(obj));
|
||||
}
|
||||
|
||||
return new Resources<Resource<?>>(resources);
|
||||
return toResources((Iterable<?>) prop.propertyValue, assembler, prop.propertyType, null);
|
||||
|
||||
} else if (prop.property.isMap()) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,12 +31,12 @@ import org.springframework.data.auditing.AuditableBeanWrapperFactory;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.repository.support.RepositoryInvoker;
|
||||
import org.springframework.data.rest.core.mapping.MethodResourceMapping;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMappings;
|
||||
import org.springframework.data.rest.core.mapping.ResourceMetadata;
|
||||
import org.springframework.data.rest.core.mapping.SearchResourceMappings;
|
||||
import org.springframework.data.rest.webmvc.support.DefaultedPageable;
|
||||
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
|
||||
import org.springframework.data.web.HateoasSortHandlerMethodArgumentResolver;
|
||||
import org.springframework.data.web.PagedResourcesAssembler;
|
||||
import org.springframework.hateoas.EntityLinks;
|
||||
import org.springframework.hateoas.Link;
|
||||
@@ -74,8 +74,6 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
|
||||
private final RepositoryEntityLinks entityLinks;
|
||||
private final ResourceMappings mappings;
|
||||
private final PagedResourcesAssembler<Object> assembler;
|
||||
private final HateoasSortHandlerMethodArgumentResolver sortResolver;
|
||||
|
||||
/**
|
||||
* Creates a new {@link RepositorySearchController} using the given {@link PagedResourcesAssembler},
|
||||
@@ -84,22 +82,19 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
* @param assembler must not be {@literal null}.
|
||||
* @param entityLinks must not be {@literal null}.
|
||||
* @param mappings must not be {@literal null}.
|
||||
* @param auditableBeanWrapperFactory must not be {@literal null}.
|
||||
*/
|
||||
@Autowired
|
||||
public RepositorySearchController(PagedResourcesAssembler<Object> assembler, RepositoryEntityLinks entityLinks,
|
||||
ResourceMappings mappings, HateoasSortHandlerMethodArgumentResolver sortResolver,
|
||||
AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
ResourceMappings mappings, AuditableBeanWrapperFactory auditableBeanWrapperFactory) {
|
||||
|
||||
super(assembler, auditableBeanWrapperFactory);
|
||||
|
||||
Assert.notNull(entityLinks, "EntityLinks must not be null!");
|
||||
Assert.notNull(mappings, "ResourceMappings must not be null!");
|
||||
Assert.notNull(sortResolver, "HateoasSortHandlerMethodArgumentResolver must not be null!");
|
||||
|
||||
this.entityLinks = entityLinks;
|
||||
this.mappings = mappings;
|
||||
this.assembler = assembler;
|
||||
this.sortResolver = sortResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +150,7 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
|
||||
RepositorySearchesResource result = new RepositorySearchesResource(resourceInformation.getDomainType());
|
||||
result.add(queryMethodLinks);
|
||||
result.add(getDefaultSelfLink());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -180,7 +176,11 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
Method method = checkExecutability(resourceInformation, search);
|
||||
Object result = executeQueryMethod(resourceInformation.getInvoker(), parameters, method, pageable, sort, assembler);
|
||||
|
||||
return new ResponseEntity<Object>(toResource(result, assembler, null), HttpStatus.OK);
|
||||
SearchResourceMappings searchMappings = resourceInformation.getSearchMappings();
|
||||
MethodResourceMapping methodMapping = searchMappings.getExportedMethodMappingForPath(search);
|
||||
Class<?> domainType = methodMapping.getReturnedDomainType();
|
||||
|
||||
return new ResponseEntity<Object>(toResource(result, assembler, domainType, null), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +189,7 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
* @param resourceInformation
|
||||
* @param parameters
|
||||
* @param repository
|
||||
* @param searcg
|
||||
* @param search
|
||||
* @param pageable
|
||||
* @param sort
|
||||
* @param assembler
|
||||
@@ -204,7 +204,8 @@ class RepositorySearchController extends AbstractRepositoryRestController {
|
||||
|
||||
Method method = checkExecutability(resourceInformation, search);
|
||||
Object result = executeQueryMethod(resourceInformation.getInvoker(), parameters, method, pageable, sort, assembler);
|
||||
Object resource = toResource(result, assembler, null);
|
||||
ResourceMetadata metadata = resourceInformation.getResourceMetadata();
|
||||
Object resource = toResource(result, assembler, metadata.getDomainType(), null);
|
||||
List<Link> links = new ArrayList<Link>();
|
||||
|
||||
if (resource instanceof Resources && ((Resources<?>) resource).getContent() != null) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.springframework.data.util.ClassTypeInformation.*;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.hateoas.core.EmbeddedWrapper;
|
||||
import org.springframework.hateoas.mvc.HeaderLinksResponseEntity;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -292,7 +294,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(TypeInformation<?> typeInformation, Object value) {
|
||||
return targetType.isAssignableFrom(typeInformation);
|
||||
return targetType.getType().isAssignableFrom(typeInformation.getType());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -352,7 +354,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.supports(typeInformation, value) || isValueTypeMatch((Resource<?>) value, getTargetType());
|
||||
return super.supports(typeInformation, value) && isValueTypeMatch((Resource<?>) value, getTargetType());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -408,7 +410,7 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
|
||||
return false;
|
||||
}
|
||||
|
||||
return super.supports(typeInformation, value) || isValueTypeMatch((Resources<?>) value, getTargetType());
|
||||
return super.supports(typeInformation, value) && isValueTypeMatch((Resources<?>) value, getTargetType());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,22 +433,31 @@ public class ResourceProcessorHandlerMethodReturnValueHandler implements Handler
|
||||
return false;
|
||||
}
|
||||
|
||||
Object element = content.iterator().next();
|
||||
TypeInformation<?> superTypeInformation = null;
|
||||
|
||||
if (!(element instanceof Resource)) {
|
||||
return false;
|
||||
for (Class<?> resourcesType : Arrays.<Class<?>> asList(resources.getClass(), Resources.class)) {
|
||||
|
||||
superTypeInformation = target.getSuperTypeInformation(resourcesType);
|
||||
|
||||
if (superTypeInformation != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> resourcesType = resources.getClass();
|
||||
|
||||
TypeInformation<?> superTypeInformation = target.getSuperTypeInformation(resourcesType);
|
||||
|
||||
if (superTypeInformation == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object element = content.iterator().next();
|
||||
TypeInformation<?> resourceTypeInformation = superTypeInformation.getComponentType();
|
||||
return ResourceProcessorWrapper.isValueTypeMatch((Resource<?>) element, resourceTypeInformation);
|
||||
|
||||
if (element instanceof Resource) {
|
||||
return ResourceProcessorWrapper.isValueTypeMatch((Resource<?>) element, resourceTypeInformation);
|
||||
} else if (element instanceof EmbeddedWrapper) {
|
||||
return resourceTypeInformation.getType().isAssignableFrom(((EmbeddedWrapper) element).getRelTargetType());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public abstract class CommonWebTests extends AbstractWebIntegrationTests {
|
||||
Link searchLink = client.getDiscoverer(response).findLinkWithRel("search", rootResourceRepresentation);
|
||||
|
||||
if (searchLink != null) {
|
||||
client.request(searchLink);
|
||||
client.follow(searchLink).andExpect(client.hasLinkWithRel("self"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class RepositorySearchControllerIntegrationTests extends AbstractControll
|
||||
ResourceSupport resource = controller.listSearches(request);
|
||||
|
||||
ResourceTester tester = ResourceTester.of(resource);
|
||||
tester.assertNumberOfLinks(5);
|
||||
tester.assertNumberOfLinks(6); // Self link included
|
||||
tester.assertHasLinkEndingWith("findFirstPersonByFirstName", "findFirstPersonByFirstName{?firstname,projection}");
|
||||
tester.assertHasLinkEndingWith("firstname", "firstname{?firstname,page,size,sort,projection}");
|
||||
tester.assertHasLinkEndingWith("lastname", "lastname{?lastname,sort,projection}");
|
||||
|
||||
@@ -48,6 +48,7 @@ import org.springframework.hateoas.PagedResources.PageMetadata;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceProcessor;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.hateoas.core.EmbeddedWrappers;
|
||||
import org.springframework.hateoas.mvc.HeaderLinksResponseEntity;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -255,6 +256,23 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTests {
|
||||
assertThat(ResourcesProcessorWrapper.isValueTypeMatch(pagedResources, type), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-479
|
||||
*/
|
||||
@Test
|
||||
public void doesNotInvokeAProcessorForASpecializedType() throws Exception {
|
||||
|
||||
EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
|
||||
Resources<Object> value = new Resources<Object>(Collections.<Object> singleton(wrappers
|
||||
.emptyCollectionOf(Object.class)));
|
||||
ResourcesProcessorWrapper wrapper = new ResourcesProcessorWrapper(new SpecialResourcesProcessor());
|
||||
|
||||
TypeInformation<Object> typeInformation = ClassTypeInformation.fromReturnTypeOf(Controller.class
|
||||
.getMethod("resourcesOfObject"));
|
||||
|
||||
assertThat(wrapper.supports(typeInformation, value), is(false));
|
||||
}
|
||||
|
||||
// Helpers ---------------------------------------------------------//
|
||||
private void invokeReturnValueHandler(String method, final Matcher<?> matcher, Object returnValue) throws Exception {
|
||||
final MethodParameter methodParam = METHOD_PARAMS.get(method);
|
||||
@@ -353,6 +371,8 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTests {
|
||||
ResponseEntity<Resource<?>> resourceResponseEntity();
|
||||
|
||||
ResponseEntity<Resources<?>> resourcesResponseEntity();
|
||||
|
||||
Resources<Object> resourcesOfObject();
|
||||
}
|
||||
|
||||
static class StringResource extends Resource<String> {
|
||||
@@ -383,7 +403,23 @@ public class ResourceProcessorHandlerMethodReturnValueHandlerUnitTests {
|
||||
|
||||
@Override
|
||||
public Resource<SampleProjection> process(Resource<SampleProjection> resource) {
|
||||
this.invoked = true;
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
|
||||
static class SpecialResources extends Resources<Object> {
|
||||
public SpecialResources() {
|
||||
super(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
static class SpecialResourcesProcessor implements ResourceProcessor<SpecialResources> {
|
||||
|
||||
boolean invoked = false;
|
||||
|
||||
@Override
|
||||
public SpecialResources process(SpecialResources resource) {
|
||||
this.invoked = true;
|
||||
return resource;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ public class LegacyRepresentationConfigIntegrationTests extends AbstractReposito
|
||||
public void returnsJsonIfConfiguredAndRequested() throws Exception {
|
||||
|
||||
mvc.perform(get("/").accept(MediaType.APPLICATION_JSON)). //
|
||||
andExpect(jsonPath("content", is(notNullValue())));
|
||||
andExpect(jsonPath("links", is(notNullValue())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,6 +60,6 @@ public class LegacyRepresentationConfigIntegrationTests extends AbstractReposito
|
||||
public void returnsJsonIfConfigured() throws Exception {
|
||||
|
||||
mvc.perform(get("/").accept(MediaType.ALL)). //
|
||||
andExpect(jsonPath("content", is(notNullValue())));
|
||||
andExpect(jsonPath("links", is(notNullValue())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,11 +576,13 @@ public class JpaWebTests extends CommonWebTests {
|
||||
// Assert results returned as specified
|
||||
client.follow(findBySortedLink.expand("title,desc")).//
|
||||
andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data (Second Edition)")).//
|
||||
andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data"));
|
||||
andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data")).//
|
||||
andExpect(client.hasLinkWithRel("self"));
|
||||
|
||||
client.follow(findBySortedLink.expand("title,asc")).//
|
||||
andExpect(jsonPath("$._embedded.books[0].title").value("Spring Data")).//
|
||||
andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data (Second Edition)"));
|
||||
andExpect(jsonPath("$._embedded.books[1].title").value("Spring Data (Second Edition)")).//
|
||||
andExpect(client.hasLinkWithRel("self"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user