From a50113afa9834d517c9605360b3d2b48cab1ff5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Wei=C3=9F?= Date: Fri, 12 Jan 2018 16:35:02 +0100 Subject: [PATCH] DATAREST-1176 - Add explicitly method annotated detection strategy --- .../CrudMethodsSupportedHttpMethods.java | 19 +++++++++++++------ .../RepositoryAwareResourceMetadata.java | 2 +- .../mapping/RepositoryDetectionStrategy.java | 12 ++++++++++++ .../RepositoryMethodResourceMapping.java | 13 +++++++++++-- .../mapping/RepositoryResourceMappings.java | 8 +++++++- ...dMethodsSupportedHttpMethodsUnitTests.java | 8 ++++++-- ...epositoryDetectionStrategiesUnitTests.java | 13 +++++++++++++ ...ositoryMethodResourceMappingUnitTests.java | 3 ++- 8 files changed, 65 insertions(+), 13 deletions(-) diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethods.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethods.java index d493ee651..62c400036 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethods.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethods.java @@ -19,7 +19,6 @@ import static org.springframework.http.HttpMethod.*; import lombok.NonNull; -import lombok.RequiredArgsConstructor; import java.lang.reflect.Method; import java.util.Collections; @@ -49,11 +48,14 @@ public class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods { * * @param crudMethods must not be {@literal null}. */ - public CrudMethodsSupportedHttpMethods(CrudMethods crudMethods) { + public CrudMethodsSupportedHttpMethods(CrudMethods crudMethods, RepositoryResourceMappings provider) { Assert.notNull(crudMethods, "CrudMethods must not be null!"); - this.exposedMethods = new DefaultExposureAwareCrudMethods(crudMethods); + boolean exportedDefault = provider.getRepositoryDetectionStrategy() + != RepositoryDetectionStrategy.RepositoryDetectionStrategies.EXPLICIT_METHOD_ANNOTATED; + + this.exposedMethods = new DefaultExposureAwareCrudMethods(crudMethods, exportedDefault); } /* @@ -139,10 +141,15 @@ public Set getMethodsFor(PersistentProperty property) { /** * @author Oliver Gierke */ - @RequiredArgsConstructor private static class DefaultExposureAwareCrudMethods implements ExposureAwareCrudMethods { private final @NonNull CrudMethods crudMethods; + private final boolean exportedDefault; + + DefaultExposureAwareCrudMethods(CrudMethods crudMethods, boolean exportedDefault) { + this.crudMethods = crudMethods; + this.exportedDefault = exportedDefault; + } /* * (non-Javadoc) @@ -180,12 +187,12 @@ public boolean exposesFindAll() { return exposes(crudMethods.getFindAllMethod()); } - private static boolean exposes(Optional method) { + private boolean exposes(Optional method) { return method.map(it -> { RestResource annotation = AnnotationUtils.findAnnotation(it, RestResource.class); - return annotation == null ? true : annotation.exported(); + return annotation == null ? exportedDefault : annotation.exported(); }).orElse(false); } diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java index ef7e42b60..4bb9c7d37 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryAwareResourceMetadata.java @@ -57,7 +57,7 @@ public RepositoryAwareResourceMetadata(PersistentEntity entity, Collection this.mapping = mapping; this.provider = provider; this.repositoryMetadata = repositoryMetadata; - this.crudMethodsSupportedHttpMethods = new CrudMethodsSupportedHttpMethods(repositoryMetadata.getCrudMethods()); + this.crudMethodsSupportedHttpMethods = new CrudMethodsSupportedHttpMethods(repositoryMetadata.getCrudMethods(), provider); } /** diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategy.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategy.java index fe4199735..7209b1442 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategy.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategy.java @@ -92,6 +92,18 @@ public boolean isExported(RepositoryMetadata metadata) { */ ANNOTATED { + @Override + public boolean isExported(RepositoryMetadata metadata) { + return isExplicitlyExported(metadata.getRepositoryInterface(), false); + } + }, + + /** + * Behaves like the annotated strategy on repository level. But it does not export all methods + * of an exported Repository. The methods have to be annotated explicitly too. + */ + EXPLICIT_METHOD_ANNOTATED { + @Override public boolean isExported(RepositoryMetadata metadata) { return isExplicitlyExported(metadata.getRepositoryInterface(), false); diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java index f885702d8..9fdb368d5 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMapping.java @@ -62,7 +62,8 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping { * @param method must not be {@literal null}. * @param resourceMapping must not be {@literal null}. */ - public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMapping, RepositoryMetadata metadata) { + public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMapping, RepositoryMetadata metadata, + RepositoryDetectionStrategy strategy) { Assert.notNull(method, "Method must not be null!"); Assert.notNull(resourceMapping, "ResourceMapping must not be null!"); @@ -70,7 +71,7 @@ public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMa RestResource annotation = AnnotationUtils.findAnnotation(method, RestResource.class); String resourceRel = resourceMapping.getRel(); - this.isExported = annotation != null ? annotation.exported() : true; + this.isExported = determineIsExported(strategy, annotation); this.rel = annotation == null || !StringUtils.hasText(annotation.rel()) ? method.getName() : annotation.rel(); this.path = annotation == null || !StringUtils.hasText(annotation.path()) ? new Path(method.getName()) : new Path(annotation.path()); @@ -84,6 +85,14 @@ public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMa this.metadata = metadata; } + private boolean determineIsExported(RepositoryDetectionStrategy strategy, RestResource annotation) { + + boolean exportedDefault = strategy + != RepositoryDetectionStrategy.RepositoryDetectionStrategies.EXPLICIT_METHOD_ANNOTATED; + + return annotation != null ? annotation.exported() : exportedDefault; + } + private static final List discoverParameterMetadata(Method method, String baseRel) { List result = new ArrayList(); diff --git a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappings.java b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappings.java index 5128ed99d..1ceb3123c 100644 --- a/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappings.java +++ b/spring-data-rest-core/src/main/java/org/springframework/data/rest/core/mapping/RepositoryResourceMappings.java @@ -40,6 +40,7 @@ public class RepositoryResourceMappings extends PersistentEntitiesResourceMappings { private final Repositories repositories; + private final RepositoryDetectionStrategy strategy; private final Map, SearchResourceMappings> searchCache = new HashMap, SearchResourceMappings>(); /** @@ -73,6 +74,7 @@ public RepositoryResourceMappings(Repositories repositories, PersistentEntities Assert.notNull(strategy, "RepositoryDetectionStrategy must not be null!"); this.repositories = repositories; + this.strategy = strategy; this.populateCache(repositories, relProvider, strategy); } @@ -118,7 +120,7 @@ public SearchResourceMappings getSearchResourceMappings(Class domainType) { if (resourceMapping.isExported()) { for (Method queryMethod : repositoryInformation.getQueryMethods()) { RepositoryMethodResourceMapping methodMapping = new RepositoryMethodResourceMapping(queryMethod, - resourceMapping, repositoryInformation); + resourceMapping, repositoryInformation, strategy); if (methodMapping.isExported()) { mappings.add(methodMapping); } @@ -156,4 +158,8 @@ public boolean hasMappingFor(Class type) { public boolean isMapped(PersistentProperty property) { return repositories.hasRepositoryFor(property.getActualType()) && super.isMapped(property); } + + public RepositoryDetectionStrategy getRepositoryDetectionStrategy() { + return strategy; + } } diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethodsUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethodsUnitTests.java index d66f22f29..a7f9c637a 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethodsUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/CrudMethodsSupportedHttpMethodsUnitTests.java @@ -25,6 +25,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.data.annotation.ReadOnlyProperty; import org.springframework.data.annotation.Reference; @@ -47,6 +48,9 @@ @RunWith(MockitoJUnitRunner.class) public class CrudMethodsSupportedHttpMethodsUnitTests { + @Mock + private RepositoryResourceMappings mappings; + @Test // DATACMNS-589, DATAREST-409 public void doesNotSupportAnyHttpMethodForEmptyRepository() { @@ -118,12 +122,12 @@ public void doesNotSupportDeleteIfNoFindOneAvailable() { assertMethodsSupported(getSupportedHttpMethodsFor(NoFindOne.class), ITEM, false, DELETE); } - private static SupportedHttpMethods getSupportedHttpMethodsFor(Class repositoryInterface) { + private SupportedHttpMethods getSupportedHttpMethodsFor(Class repositoryInterface) { RepositoryMetadata metadata = new DefaultRepositoryMetadata(repositoryInterface); CrudMethods crudMethods = new DefaultCrudMethods(metadata); - return new CrudMethodsSupportedHttpMethods(crudMethods); + return new CrudMethodsSupportedHttpMethods(crudMethods, mappings); } private static void assertMethodsSupported(SupportedHttpMethods methods, ResourceType type, boolean supported, diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategiesUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategiesUnitTests.java index 7c656c018..b270b3134 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategiesUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryDetectionStrategiesUnitTests.java @@ -89,6 +89,19 @@ public void annotatedHonorsAnnotationsOnly() { }); } + @Test // DATAREST-1176 + public void onlyExplicitAnnotatedMethodsAreExposed() { + + assertExposures(EXPLICIT_METHOD_ANNOTATED, new HashMap, Boolean>() { + { + put(AnnotatedRepository.class, true); + put(HiddenRepository.class, false); + put(PublicRepository.class, false); + put(PackageProtectedRepository.class, false); + } + }); + } + private static void assertExposures(RepositoryDetectionStrategy strategy, Map, Boolean> expected) { for (Entry, Boolean> entry : expected.entrySet()) { diff --git a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java index 5c85ce12f..425579469 100755 --- a/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java +++ b/spring-data-rest-core/src/test/java/org/springframework/data/rest/core/mapping/RepositoryMethodResourceMappingUnitTests.java @@ -131,7 +131,8 @@ public void doesNotIncludePageableAsParameter() throws Exception { } private RepositoryMethodResourceMapping getMappingFor(Method method) { - return new RepositoryMethodResourceMapping(method, resourceMapping, metadata); + RepositoryDetectionStrategy strategy = RepositoryDetectionStrategies.DEFAULT; + return new RepositoryMethodResourceMapping(method, resourceMapping, metadata, strategy); } static class Person {}