DATAREST-1176 - Add explicitly method annotated detection strategy
This commit is contained in:
committed by
Oliver Gierke
parent
b01ea05164
commit
d688e70ade
@@ -19,7 +19,6 @@ import static org.springframework.data.rest.core.mapping.ResourceType.*;
|
||||
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 class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods {
|
||||
/**
|
||||
* @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 class CrudMethodsSupportedHttpMethods implements SupportedHttpMethods {
|
||||
return exposes(crudMethods.getFindAllMethod());
|
||||
}
|
||||
|
||||
private static boolean exposes(Optional<Method> method) {
|
||||
private boolean exposes(Optional<Method> 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);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ class RepositoryAwareResourceMetadata implements ResourceMetadata {
|
||||
this.mapping = mapping;
|
||||
this.provider = provider;
|
||||
this.repositoryMetadata = repositoryMetadata;
|
||||
this.crudMethodsSupportedHttpMethods = new CrudMethodsSupportedHttpMethods(repositoryMetadata.getCrudMethods());
|
||||
this.crudMethodsSupportedHttpMethods = new CrudMethodsSupportedHttpMethods(repositoryMetadata.getCrudMethods(), provider);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,6 +92,18 @@ public interface RepositoryDetectionStrategy {
|
||||
*/
|
||||
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);
|
||||
|
||||
@@ -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 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
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 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
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<ParameterMetadata> discoverParameterMetadata(Method method, String baseRel) {
|
||||
|
||||
List<ParameterMetadata> result = new ArrayList<ParameterMetadata>();
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.util.Assert;
|
||||
public class RepositoryResourceMappings extends PersistentEntitiesResourceMappings {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final RepositoryDetectionStrategy strategy;
|
||||
private final Map<Class<?>, SearchResourceMappings> searchCache = new HashMap<Class<?>, SearchResourceMappings>();
|
||||
|
||||
/**
|
||||
@@ -73,6 +74,7 @@ public class RepositoryResourceMappings extends PersistentEntitiesResourceMappin
|
||||
Assert.notNull(strategy, "RepositoryDetectionStrategy must not be null!");
|
||||
|
||||
this.repositories = repositories;
|
||||
this.strategy = strategy;
|
||||
this.populateCache(repositories, relProvider, strategy);
|
||||
}
|
||||
|
||||
@@ -118,7 +120,7 @@ public class RepositoryResourceMappings extends PersistentEntitiesResourceMappin
|
||||
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 class RepositoryResourceMappings extends PersistentEntitiesResourceMappin
|
||||
public boolean isMapped(PersistentProperty<?> property) {
|
||||
return repositories.hasRepositoryFor(property.getActualType()) && super.isMapped(property);
|
||||
}
|
||||
|
||||
public RepositoryDetectionStrategy getRepositoryDetectionStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.springframework.data.rest.core.mapping.ResourceType.*;
|
||||
import static org.springframework.http.HttpMethod.*;
|
||||
|
||||
@@ -23,8 +24,10 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
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 +50,14 @@ import org.springframework.http.HttpMethod;
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CrudMethodsSupportedHttpMethodsUnitTests {
|
||||
|
||||
@Mock
|
||||
private RepositoryResourceMappings mappings;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(mappings.exposeMethodsByDefault()).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test // DATACMNS-589, DATAREST-409
|
||||
public void doesNotSupportAnyHttpMethodForEmptyRepository() {
|
||||
|
||||
@@ -118,12 +129,12 @@ public class CrudMethodsSupportedHttpMethodsUnitTests {
|
||||
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,
|
||||
|
||||
@@ -89,6 +89,19 @@ public class RepositoryDetectionStrategiesUnitTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAREST-1176
|
||||
public void onlyExplicitAnnotatedMethodsAreExposed() {
|
||||
|
||||
assertExposures(EXPLICIT_METHOD_ANNOTATED, new HashMap<Class<?>, Boolean>() {
|
||||
{
|
||||
put(AnnotatedRepository.class, true);
|
||||
put(HiddenRepository.class, false);
|
||||
put(PublicRepository.class, false);
|
||||
put(PackageProtectedRepository.class, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void assertExposures(RepositoryDetectionStrategy strategy, Map<Class<?>, Boolean> expected) {
|
||||
|
||||
for (Entry<Class<?>, Boolean> entry : expected.entrySet()) {
|
||||
|
||||
@@ -131,7 +131,8 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
}
|
||||
|
||||
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 {}
|
||||
|
||||
Reference in New Issue
Block a user