From 175f9eab10219c0e6183c993877acf3cc6eb7546 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sat, 29 Jun 2013 17:09:47 +0200 Subject: [PATCH] DATAREST-99 - Updated RepositoryController to use new mapping API. RepositoryController now uses the new mapping API to not expose non-public repositories anymore. Added integration test for that in the JPA module. --- .../RepositoryCollectionResourceMapping.java | 12 ++++--- ...oryCollectionResourceMappingUnitTests.java | 11 +++++++ .../rest/webmvc/RepositoryController.java | 33 +++++++++++-------- .../webmvc/AbstractWebIntegrationTests.java | 13 ++++++++ .../data/rest/webmvc/jpa/CreditCard.java | 28 ++++++++++++++++ .../rest/webmvc/jpa/CreditCardRepository.java | 25 ++++++++++++++ .../data/rest/webmvc/jpa/JpaWebTests.java | 18 ++++++++++ 7 files changed, 123 insertions(+), 17 deletions(-) create mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCard.java create mode 100644 spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCardRepository.java diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMapping.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMapping.java index deab592e0..327678487 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMapping.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMapping.java @@ -15,6 +15,8 @@ */ package org.springframework.data.rest.repository.mapping; +import java.lang.reflect.Modifier; + import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.rest.core.Path; import org.springframework.data.rest.repository.annotation.RestResource; @@ -35,6 +37,7 @@ public class RepositoryCollectionResourceMapping implements CollectionResourceMa private final RestResource annotation; private final CollectionResourceMapping domainTypeMapping; + private final boolean repositoryIsExportCandidate; public RepositoryCollectionResourceMapping(Class repositoryType) { this(repositoryType, new EvoInflectorRelProvider()); @@ -55,6 +58,7 @@ public class RepositoryCollectionResourceMapping implements CollectionResourceMa this.annotation = AnnotationUtils.findAnnotation(repositoryType, RestResource.class); this.domainTypeMapping = new TypeBasedCollectionResourceMapping(RepositoriesUtils.getDomainType(repositoryType), relProvider); + this.repositoryIsExportCandidate = Modifier.isPublic(repositoryType.getModifiers()); } /* @@ -63,9 +67,9 @@ public class RepositoryCollectionResourceMapping implements CollectionResourceMa */ @Override public Path getPath() { - - return annotation == null || !StringUtils.hasText(annotation.path()) ? domainTypeMapping.getPath() - : new Path(annotation.path()); + + return annotation == null || !StringUtils.hasText(annotation.path()) ? domainTypeMapping.getPath() : new Path( + annotation.path()); } /* @@ -92,6 +96,6 @@ public class RepositoryCollectionResourceMapping implements CollectionResourceMa */ @Override public Boolean isExported() { - return annotation == null ? domainTypeMapping.isExported() : annotation.exported(); + return annotation == null ? repositoryIsExportCandidate && domainTypeMapping.isExported() : annotation.exported(); } } diff --git a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMappingUnitTests.java b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMappingUnitTests.java index 696d8ec55..a3a94cacf 100644 --- a/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMappingUnitTests.java +++ b/spring-data-rest-repository/src/test/java/org/springframework/data/rest/repository/mapping/RepositoryCollectionResourceMappingUnitTests.java @@ -64,6 +64,13 @@ public class RepositoryCollectionResourceMappingUnitTests { assertThat(mapping.isExported(), is(true)); } + @Test + public void doesNotExposeRepositoryForPublicDomainTypeIfRepoIsPackageProtected() { + + ResourceMapping mapping = new RepositoryCollectionResourceMapping(PackageProtectedRepository.class); + assertThat(mapping.isExported(), is(false)); + } + public static class Person {} @RestResource(path = "bar", rel = "foo", exported = false) @@ -75,4 +82,8 @@ public class RepositoryCollectionResourceMappingUnitTests { @RestResource(path = "trumpsAll") interface AnnotatedAnnotatedPersonRepository extends Repository {} + + public static class PublicClass {} + + static interface PackageProtectedRepository extends Repository {} } 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 a7737cebb..33c9cd94d 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 @@ -17,50 +17,57 @@ package org.springframework.data.rest.webmvc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.repository.support.Repositories; -import org.springframework.data.rest.config.RepositoryRestConfiguration; -import org.springframework.data.rest.config.ResourceMapping; +import org.springframework.data.rest.repository.mapping.ResourceMappings; +import org.springframework.data.rest.repository.mapping.ResourceMetadata; import org.springframework.data.web.PagedResourcesAssembler; import org.springframework.hateoas.EntityLinks; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; -import static org.springframework.data.rest.repository.support.ResourceMappingUtils.getResourceMapping; - /** * @author Jon Brisbin * @author Oliver Gierke */ @RestController -@SuppressWarnings("deprecation") public class RepositoryController extends AbstractRepositoryRestController { private final Repositories repositories; - private final RepositoryRestConfiguration config; private final EntityLinks entityLinks; + private final ResourceMappings mappings; @Autowired - public RepositoryController(Repositories repositories, RepositoryRestConfiguration config, EntityLinks entityLinks, - PagedResourcesAssembler assembler, PersistentEntityResourceAssembler perAssembler) { + public RepositoryController(PagedResourcesAssembler assembler, + PersistentEntityResourceAssembler perAssembler, Repositories repositories, EntityLinks entityLinks, + ResourceMappings mappings) { super(assembler, perAssembler); this.repositories = repositories; - this.config = config; this.entityLinks = entityLinks; + this.mappings = mappings; } + /** + * Lists all repositories exported by creating a link list pointing to resources exposing the repositories. + * + * @return + */ + @ResponseBody @RequestMapping(value = "/", method = RequestMethod.GET, // produces = { "application/json", "application/x-spring-data-compact+json" }) - @ResponseBody - public RepositoryLinksResource listRepositories() throws ResourceNotFoundException { + public RepositoryLinksResource listRepositories() { + RepositoryLinksResource resource = new RepositoryLinksResource(); + for (Class domainType : repositories) { - ResourceMapping repoMapping = getResourceMapping(config, repositories.getRepositoryInformationFor(domainType)); - if (repoMapping.isExported()) { + + ResourceMetadata metadata = mappings.getMappingFor(domainType); + if (metadata.isExported()) { resource.add(entityLinks.linkToCollectionResource(domainType)); } } + return resource; } } diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java index 86c020e08..a5e6b4ec4 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/AbstractWebIntegrationTests.java @@ -133,6 +133,19 @@ public abstract class AbstractWebIntegrationTests { }; } + protected ResultMatcher doesNotHaveLinkWithRel(final String rel) { + + return new ResultMatcher() { + + @Override + public void match(MvcResult result) throws Exception { + String s = result.getResponse().getContentAsString(); + assertThat("Expected not to find link with rel " + rel + " but found one in " + s, + links.findLinkWithRel(rel, s), nullValue()); + } + }; + } + @Test public void exposesRootResource() throws Exception { diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCard.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCard.java new file mode 100644 index 000000000..8e028736d --- /dev/null +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCard.java @@ -0,0 +1,28 @@ +/* + * Copyright 2013 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.jpa; + +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * @author Oliver Gierke + */ +@Entity +public class CreditCard { + + @Id Long id; +} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCardRepository.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCardRepository.java new file mode 100644 index 000000000..49f50c552 --- /dev/null +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/CreditCardRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2013 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.jpa; + +import org.springframework.data.repository.CrudRepository; + +/** + * @author Oliver Gierke + */ +interface CreditCardRepository extends CrudRepository { + +} diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java index 6e86445ef..363854f86 100644 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/jpa/JpaWebTests.java @@ -15,9 +15,14 @@ */ package org.springframework.data.rest.webmvc.jpa; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + import java.util.Arrays; import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.rest.repository.mapping.ResourceMappings; import org.springframework.data.rest.webmvc.AbstractWebIntegrationTests; import org.springframework.hateoas.Link; import org.springframework.mock.web.MockHttpServletResponse; @@ -33,6 +38,8 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class JpaWebTests extends AbstractWebIntegrationTests { + @Autowired ResourceMappings mappings; + /* * (non-Javadoc) * @see org.springframework.data.rest.webmvc.AbstractWebIntegrationTests#expectedRootLinkRels() @@ -42,6 +49,17 @@ public class JpaWebTests extends AbstractWebIntegrationTests { return Arrays.asList("people"); } + /** + * @see DATAREST-99 + */ + @Test + public void doesNotExposeCreditCardRepository() throws Exception { + + mvc.perform(get("/")). // + andExpect(status().isOk()). // + andExpect(doesNotHaveLinkWithRel(mappings.getMappingFor(CreditCard.class).getRel())); + } + @Test public void accessPersons() throws Exception {