diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/BaseUri.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/BaseUri.java index 8bce1fc59..f1cc177cc 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/BaseUri.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/BaseUri.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-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. @@ -111,7 +111,6 @@ public class BaseUri { Assert.notNull(lookupPath, "Lookup path must not be null!"); - lookupPath = lookupPath.contains("{") ? lookupPath.substring(0, lookupPath.indexOf('{')) : lookupPath; lookupPath = trimTrailingCharacter(lookupPath, '/'); if (!baseUri.isAbsolute()) { diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssembler.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssembler.java index b5892e951..9a705a9c4 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssembler.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssembler.java @@ -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. @@ -24,7 +24,7 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.PersistentPropertyAccessor; import org.springframework.data.mapping.SimpleAssociationHandler; -import org.springframework.data.repository.support.Repositories; +import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.rest.core.mapping.ResourceMappings; import org.springframework.data.rest.core.mapping.ResourceMetadata; import org.springframework.data.rest.webmvc.PersistentEntityResource.Builder; @@ -44,7 +44,7 @@ import org.springframework.util.Assert; */ public class PersistentEntityResourceAssembler implements ResourceAssembler { - private final Repositories repositories; + private final PersistentEntities entities; private final EntityLinks entityLinks; private final Projector projector; private final ResourceMappings mappings; @@ -53,20 +53,20 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler entity = repositories.getPersistentEntity(source.getClass()); + PersistentEntity entity = entities.getPersistentEntity(source.getClass()); return PersistentEntityResource.build(instance, entity).// withEmbedded(getEmbeddedResources(source)).// - withLink(getSelfLinkFor(source)); + withLink(getSelfLinkFor(source)).// + withLink(getSingleResourceLinkTo(source)); } /** @@ -115,7 +116,7 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler entity = repositories.getPersistentEntity(instance.getClass()); + PersistentEntity entity = entities.getPersistentEntity(instance.getClass()); final List associationProjections = new ArrayList(); final PersistentPropertyAccessor accessor = entity.getPropertyAccessor(instance); @@ -183,20 +184,23 @@ public class PersistentEntityResourceAssembler implements ResourceAssembler instanceType = instance.getClass(); - PersistentEntity entity = repositories.getPersistentEntity(instanceType); + PersistentEntity entity = entities.getPersistentEntity(instanceType); if (entity == null) { - throw new IllegalArgumentException(String.format("Cannot create self link for %s! No persistent entity found!", - instanceType)); + throw new IllegalArgumentException( + String.format("Cannot create self link for %s! No persistent entity found!", instanceType)); } Object id = entity.getIdentifierAccessor(instance).getIdentifier(); - Link resourceLink = entityLinks.linkToSingleResource(entity.getType(), id); - return new Link(resourceLink.getHref(), Link.REL_SELF); + return entityLinks.linkToSingleResource(entity.getType(), id); } } diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceAssemblerArgumentResolver.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceAssemblerArgumentResolver.java index 4dfe880e7..d5ef70b66 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceAssemblerArgumentResolver.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/config/PersistentEntityResourceAssemblerArgumentResolver.java @@ -16,6 +16,7 @@ package org.springframework.data.rest.webmvc.config; import org.springframework.core.MethodParameter; +import org.springframework.data.mapping.context.PersistentEntities; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.repository.support.Repositories; import org.springframework.data.rest.core.mapping.ResourceMappings; @@ -36,7 +37,7 @@ import org.springframework.web.method.support.ModelAndViewContainer; */ public class PersistentEntityResourceAssemblerArgumentResolver implements HandlerMethodArgumentResolver { - private final Repositories repositories; + private final PersistentEntities entities; private final EntityLinks entityLinks; private final ProjectionDefinitions projectionDefinitions; private final ProjectionFactory projectionFactory; @@ -46,20 +47,20 @@ public class PersistentEntityResourceAssemblerArgumentResolver implements Handle * Creates a new {@link PersistentEntityResourceAssemblerArgumentResolver} for the given {@link Repositories}, * {@link EntityLinks}, {@link ProjectionDefinitions} and {@link ProjectionFactory}. * - * @param repositories must not be {@literal null}. + * @param entities must not be {@literal null}. * @param entityLinks must not be {@literal null}. * @param projectionDefinitions must not be {@literal null}. * @param projectionFactory must not be {@literal null}. */ - public PersistentEntityResourceAssemblerArgumentResolver(Repositories repositories, EntityLinks entityLinks, + public PersistentEntityResourceAssemblerArgumentResolver(PersistentEntities entities, EntityLinks entityLinks, ProjectionDefinitions projectionDefinitions, ProjectionFactory projectionFactory, ResourceMappings mappings) { - Assert.notNull(repositories, "Repositories must not be null!"); + Assert.notNull(entities, "PersistentEntities must not be null!"); Assert.notNull(entityLinks, "EntityLinks must not be null!"); Assert.notNull(projectionDefinitions, "ProjectionDefinitions must not be null!"); Assert.notNull(projectionFactory, "ProjectionFactory must not be null!"); - this.repositories = repositories; + this.entities = entities; this.entityLinks = entityLinks; this.projectionDefinitions = projectionDefinitions; this.projectionFactory = projectionFactory; @@ -87,6 +88,6 @@ public class PersistentEntityResourceAssemblerArgumentResolver implements Handle PersistentEntityProjector projector = new PersistentEntityProjector(projectionDefinitions, projectionFactory, projectionParameter, mappings); - return new PersistentEntityResourceAssembler(repositories, entityLinks, projector, mappings); + return new PersistentEntityResourceAssembler(entities, entityLinks, projector, mappings); } } 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 9e95e2303..97f24ee1b 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 @@ -141,7 +141,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; @Configuration @EnableHypermediaSupport(type = HypermediaType.HAL) @ComponentScan(basePackageClasses = RepositoryRestController.class, - includeFilters = @Filter(BasePathAwareController.class), useDefaultFilters = false) + includeFilters = @Filter(BasePathAwareController.class) , useDefaultFilters = false) @ImportResource("classpath*:META-INF/spring-data-rest/**/*.xml") @Import(SpringDataJacksonConfiguration.class) public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebConfiguration { @@ -171,8 +171,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon List> arrayList = new ArrayList>(); - for (MappingContext context : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, - MappingContext.class).values()) { + for (MappingContext context : BeanFactoryUtils + .beansOfTypeIncludingAncestors(applicationContext, MappingContext.class).values()) { arrayList.add(context); } @@ -406,7 +406,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon RestMediaTypes.JSON_PATCH_JSON, RestMediaTypes.MERGE_PATCH_JSON, // RestMediaTypes.SPRING_DATA_VERBOSE_JSON, RestMediaTypes.SPRING_DATA_COMPACT_JSON)); - TypeConstrainedMappingJackson2HttpMessageConverter jacksonConverter = new ResourceSupportHttpMessageConverter(order); + TypeConstrainedMappingJackson2HttpMessageConverter jacksonConverter = new ResourceSupportHttpMessageConverter( + order); jacksonConverter.setObjectMapper(objectMapper()); jacksonConverter.setSupportedMediaTypes(mediaTypes); @@ -578,8 +579,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon @Bean public RepositoryInvokerFactory repositoryInvokerFactory() { - return new UnwrappingRepositoryInvokerFactory(new DefaultRepositoryInvokerFactory(repositories(), - defaultConversionService())); + return new UnwrappingRepositoryInvokerFactory( + new DefaultRepositoryInvokerFactory(repositories(), defaultConversionService())); } @Bean @@ -661,7 +662,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon projectionFactory.setResourceLoader(applicationContext); PersistentEntityResourceAssemblerArgumentResolver peraResolver = new PersistentEntityResourceAssemblerArgumentResolver( - repositories(), entityLinks(), config().projectionConfiguration(), projectionFactory, resourceMappings()); + persistentEntities(), entityLinks(), config().projectionConfiguration(), projectionFactory, resourceMappings()); HateoasPageableHandlerMethodArgumentResolver pageableResolver = pageableResolver(); HandlerMethodArgumentResolver defaultedPageableResolver = new DefaultedPageableHandlerMethodArgumentResolver( @@ -669,8 +670,8 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon return Arrays.asList(defaultedPageableResolver, pageableResolver, sortResolver(), serverHttpRequestMethodArgumentResolver(), repoRequestArgumentResolver(), persistentEntityArgumentResolver(), - resourceMetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE, - peraResolver, backendIdHandlerMethodArgumentResolver(), eTagArgumentResolver()); + resourceMetadataHandlerMethodArgumentResolver(), HttpMethodHandlerMethodArgumentResolver.INSTANCE, peraResolver, + backendIdHandlerMethodArgumentResolver(), eTagArgumentResolver()); } @Autowired GeoModule geoModule; diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractControllerIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractControllerIntegrationTests.java index 4edfc313a..82fa80f71 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractControllerIntegrationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractControllerIntegrationTests.java @@ -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. @@ -53,7 +53,7 @@ public abstract class AbstractControllerIntegrationTests { @Bean public PersistentEntityResourceAssembler persistentEntityResourceAssembler() { - return new PersistentEntityResourceAssembler(repositories(), entityLinks(), StubProjector.INSTANCE, + return new PersistentEntityResourceAssembler(persistentEntities(), entityLinks(), StubProjector.INSTANCE, resourceMappings()); } } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/BaseUriUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/BaseUriUnitTests.java index 7bbae6fe9..a8bbf6416 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/BaseUriUnitTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/BaseUriUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-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. @@ -21,8 +21,6 @@ import static org.junit.Assert.*; import java.net.URI; import org.junit.Test; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.web.context.request.ServletWebRequest; /** * Unit tests for {@link BaseUri}. @@ -89,26 +87,4 @@ public class BaseUriUnitTests { assertThat(uri.getRepositoryLookupPath("/foo/people"), is("/people")); assertThat(uri.getRepositoryLookupPath("/foo/people/"), is("/people")); } - - /** - * @see DATAREST-300 - */ - @Test - public void stripsTemplateVariablesFromPath() { - - BaseUri uri = new BaseUri(URI.create("foo")); - assertThat(uri.getRepositoryLookupPath("/foo/bar{?projection}"), is("/bar")); - } - - /** - * @see DATAREST-318 - */ - @Test - public void stripsTemplateVariablesFromRequest() { - - BaseUri uri = new BaseUri(URI.create("foo")); - - ServletWebRequest request = new ServletWebRequest(new MockHttpServletRequest("GET", "/foo/bar{?projection}")); - assertThat(uri.getRepositoryLookupPath(request), is("/bar")); - } } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java new file mode 100644 index 000000000..68a602274 --- /dev/null +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/PersistentEntityResourceAssemblerIntegrationTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 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 static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.math.BigInteger; + +import org.hamcrest.Matchers; +import org.junit.Test; +import org.mockito.internal.stubbing.answers.ReturnsArgumentAt; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mapping.context.PersistentEntities; +import org.springframework.data.rest.webmvc.AbstractControllerIntegrationTests.TestConfiguration; +import org.springframework.data.rest.webmvc.mongodb.MongoDbRepositoryConfig; +import org.springframework.data.rest.webmvc.mongodb.User; +import org.springframework.data.rest.webmvc.support.Projector; +import org.springframework.hateoas.EntityLinks; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.Links; +import org.springframework.test.context.ContextConfiguration; + +/** + * Integration tests for {@link PersistentEntityResourceAssembler}. + * + * @author Oliver Gierke + */ +@ContextConfiguration(classes = { TestConfiguration.class, MongoDbRepositoryConfig.class }) +public class PersistentEntityResourceAssemblerIntegrationTests extends AbstractControllerIntegrationTests { + + @Autowired PersistentEntities entities; + @Autowired EntityLinks entityLinks; + + /** + * @see DATAREST-609 + */ + @Test + public void addsSelfAndSingleResourceLinkToResourceByDefault() { + + Projector projector = mock(Projector.class); + + when(projector.projectExcerpt(anyObject())).thenAnswer(new ReturnsArgumentAt(0)); + + PersistentEntityResourceAssembler assembler = new PersistentEntityResourceAssembler(entities, entityLinks, + projector, mappings); + + User user = new User(); + user.id = BigInteger.valueOf(4711); + + Links links = new Links(assembler.toResource(user).getLinks()); + + assertThat(links, is(Matchers. iterableWithSize(2))); + assertThat(links.getLink("self").getVariables(), is(Matchers.empty())); + assertThat(links.getLink("user").getVariableNames(), is(hasItem("projection"))); + } + +} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java index dff1906ff..4b747386d 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java @@ -220,4 +220,17 @@ public class RepositoryRestHandlerMappingUnitTests { assertThat(method, is(nullValue())); } + + /** + * @see DATAREST-609 + */ + @Test + public void rejectsUnexpandedUriTemplateWithNotFound() throws Exception { + + when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true); + + mockRequest = new MockHttpServletRequest("GET", "/people{?projection}"); + + assertThat(handlerMapping.getHandler(mockRequest), is(nullValue())); + } } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/mongodb/UserSummary.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/mongodb/UserSummary.java new file mode 100644 index 000000000..6eb6b7cc4 --- /dev/null +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/mongodb/UserSummary.java @@ -0,0 +1,29 @@ +/* + * Copyright 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.mongodb; + +import org.springframework.data.rest.core.config.Projection; + +/** + * @author Oliver Gierke + */ +@Projection(types = User.class) +public interface UserSummary { + + String getFirstname(); + + String getLastname(); +} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/BackendIdConverterHandlerMethodArgumentResolverIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/BackendIdConverterHandlerMethodArgumentResolverIntegrationTests.java index c3f1f126e..d69100e9a 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/BackendIdConverterHandlerMethodArgumentResolverIntegrationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/support/BackendIdConverterHandlerMethodArgumentResolverIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 the original author or authors. + * Copyright 2014-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. @@ -39,25 +39,11 @@ import org.springframework.web.context.request.ServletWebRequest; * @author Oliver Gierke */ @ContextConfiguration(classes = JpaRepositoryConfig.class) -public class BackendIdConverterHandlerMethodArgumentResolverIntegrationTests extends AbstractControllerIntegrationTests { +public class BackendIdConverterHandlerMethodArgumentResolverIntegrationTests + extends AbstractControllerIntegrationTests { @Autowired BackendIdHandlerMethodArgumentResolver resolver; - /** - * @see DATAREST-267, DATAREST-268 - */ - @Test - public void stripsUriTemplateVariablesFromUri() throws Exception { - - Method method = ReflectionUtils.findMethod(SampleController.class, "resolveId", Serializable.class); - MethodParameter parameter = new MethodParameter(method, 0); - NativeWebRequest request = new ServletWebRequest(new MockHttpServletRequest("GET", "/orders/5{?projection}")); - - Object resolvedId = resolver.resolveArgument(parameter, null, request, null); - - assertThat(resolvedId, is((Object) "5")); - } - /** * @see DATAREST-155 */