DATAREST-467 - RepositoryEntityLinks now exposes methods to create links to search resources.
RepositoryEntityLinks now exposes methods to obtain links to all search resources and individual ones, including overloads to pre-expand Pageable and Sort parameters potentially contained in the method signature. Search links now also contain a projection template variable if the type returned by the query method backing the search resource has projections registered.
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A {@link ResourceMapping} that is backed by a {@link Method}.
|
||||
@@ -44,4 +47,13 @@ public interface MethodResourceMapping extends ResourceMapping {
|
||||
* @return
|
||||
*/
|
||||
boolean isSortableResource();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
* @since 2.3
|
||||
*/
|
||||
Class<?> getReturnedDomainType();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.core.annotation.RestResource;
|
||||
@@ -48,6 +49,7 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
private final Method method;
|
||||
private final boolean paging;
|
||||
private final boolean sorting;
|
||||
private final RepositoryMetadata metadata;
|
||||
|
||||
private final List<ParameterMetadata> parameterMetadata;
|
||||
|
||||
@@ -57,7 +59,7 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
* @param method must not be {@literal null}.
|
||||
* @param resourceMapping must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMapping) {
|
||||
public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMapping, RepositoryMetadata metadata) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
Assert.notNull(resourceMapping, "ResourceMapping must not be null!");
|
||||
@@ -76,6 +78,7 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
|
||||
this.paging = parameterTypes.contains(Pageable.class);
|
||||
this.sorting = parameterTypes.contains(Sort.class);
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
private static final List<ParameterMetadata> discoverParameterMetadata(Method method, String baseRel) {
|
||||
@@ -162,4 +165,13 @@ class RepositoryMethodResourceMapping implements MethodResourceMapping {
|
||||
public ResourceDescription getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.MethodResourceMapping#getProjectionSourceType()
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getReturnedDomainType() {
|
||||
return metadata.getReturnedDomainClass(method);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ public class RepositoryResourceMappings implements ResourceMappings {
|
||||
if (resourceMapping.isExported()) {
|
||||
for (Method queryMethod : repositoryInformation.getQueryMethods()) {
|
||||
RepositoryMethodResourceMapping methodMapping = new RepositoryMethodResourceMapping(queryMethod,
|
||||
resourceMapping);
|
||||
resourceMapping, repositoryInformation);
|
||||
if (methodMapping.isExported()) {
|
||||
mappings.add(methodMapping);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -17,9 +17,11 @@ package org.springframework.data.rest.core.mapping;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -77,6 +79,46 @@ public class SearchResourceMappings implements Iterable<MethodResourceMapping>,
|
||||
return mapping == null ? null : mapping.getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mappings for all exported query methods.
|
||||
*
|
||||
* @return
|
||||
* @since 2.3
|
||||
*/
|
||||
public Iterable<MethodResourceMapping> getExportedMappings() {
|
||||
|
||||
Set<MethodResourceMapping> result = new HashSet<MethodResourceMapping>(mappings.values().size());
|
||||
|
||||
for (MethodResourceMapping mapping : this) {
|
||||
if (mapping.isExported()) {
|
||||
result.add(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MappingResourceMetadata} for the given relation name.
|
||||
*
|
||||
* @param rel must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 2.3
|
||||
*/
|
||||
public MethodResourceMapping getExportedMethodMappingForRel(String rel) {
|
||||
|
||||
Assert.hasText(rel, "Rel must not be null or empty!");
|
||||
|
||||
for (MethodResourceMapping mapping : this) {
|
||||
|
||||
if (mapping.isExported() && mapping.getRel().endsWith(rel)) {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.core.mapping.ResourceMapping#getPath()
|
||||
|
||||
@@ -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.
|
||||
@@ -45,7 +45,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void defaultsMappingToMethodName() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLastname", String.class);
|
||||
ResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
ResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("findByLastname")));
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void usesConfiguredNameWithLeadingSlash() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByFirstname", String.class);
|
||||
ResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
ResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("bar")));
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void doesNotDiscoverAnyParametersIfNotAnnotated() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLastname", String.class);
|
||||
MethodResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
MethodResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.getParametersMetadata().getParameterNames(), is(emptyIterable()));
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void resolvesParameterNamesIfNotAnnotated() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByFirstname", String.class);
|
||||
MethodResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
MethodResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.getParametersMetadata().getParameterNames(), hasSize(1));
|
||||
assertThat(mapping.getParametersMetadata().getParameterNames(), hasItem("firstname"));
|
||||
@@ -91,7 +91,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void considersPagingFinderAPagingResource() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByEmailAddress", String.class, Pageable.class);
|
||||
MethodResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
MethodResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.isPagingResource(), is(true));
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void usesMethodNameAsRelFallbackEvenIfPathIsConfigured() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByEmailAddress", String.class, Pageable.class);
|
||||
MethodResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
MethodResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.getRel(), is("findByEmailAddress"));
|
||||
}
|
||||
@@ -112,16 +112,33 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
public void considersResourceSortableIfSortParameterIsPresent() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByEmailAddress", String.class, Sort.class);
|
||||
RepositoryMethodResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
RepositoryMethodResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.isSortableResource(), is(true));
|
||||
|
||||
method = PersonRepository.class.getMethod("findByEmailAddress", String.class, Pageable.class);
|
||||
mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.isSortableResource(), is(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAREST-467
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void returnsDomainTypeAsProjectionSourceType() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLastname", String.class);
|
||||
MethodResourceMapping mapping = getMappingFor(method);
|
||||
|
||||
assertThat(mapping.getReturnedDomainType(), is(equalTo((Class) Person.class)));
|
||||
}
|
||||
|
||||
private RepositoryMethodResourceMapping getMappingFor(Method method) {
|
||||
return new RepositoryMethodResourceMapping(method, resourceMapping, metadata);
|
||||
}
|
||||
|
||||
static class Person {}
|
||||
|
||||
interface PersonRepository extends Repository<Person, Long> {
|
||||
@@ -138,5 +155,7 @@ public class RepositoryMethodResourceMappingUnitTests {
|
||||
Page<Person> findByEmailAddress(String email, Pageable pageable);
|
||||
|
||||
Page<Person> findByEmailAddress(String email, Sort pageable);
|
||||
|
||||
int countByLastname(String lastname);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user