DATAREST-93 - Further fixes in repository mappings.
Simplified new RepositoryMappings infrastructure. Integrated EvoInflectionRelProvider to build collection resource rels. Bumped version number to 2.0 as we're going to break backwards compatibility with the next release to straighten out the rel construction and mapping.
This commit is contained in:
@@ -25,6 +25,7 @@ ext {
|
||||
hibernateVersion = "4.2.0.Final"
|
||||
hibernateValidatorVersion = "4.3.1.Final"
|
||||
hsqldbVersion = "2.2.9"
|
||||
evoVersion="1.0.1"
|
||||
|
||||
// Supporting libraries
|
||||
cglibVersion = "2.2.2"
|
||||
@@ -182,6 +183,9 @@ project("spring-data-rest-repository") {
|
||||
// JSR 303 Validation
|
||||
compile("javax.validation:validation-api:1.0.0.GA", optional)
|
||||
|
||||
// Evo Inflector
|
||||
runtime "org.atteo:evo-inflector:${evoVersion}"
|
||||
|
||||
// Testing
|
||||
testCompile "org.hsqldb:hsqldb:$hsqldbVersion"
|
||||
testCompile "org.hibernate:hibernate-entitymanager:$hibernateVersion"
|
||||
|
||||
@@ -1 +1 @@
|
||||
version = 1.1.0.BUILD-SNAPSHOT
|
||||
version = 2.0.0.BUILD-SNAPSHOT
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple value object to build up (URI) paths. Allows easy concatenation of {@link String}s and will take care of
|
||||
* removal of whitespace and reducing slashes to single ones.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class Path {
|
||||
|
||||
private static final String SLASH = "/";
|
||||
|
||||
private final String path;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Path} from the given {@link String}.
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
public Path(String path) {
|
||||
this(path, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Path} from the given string and potentially bypasses the cleanup.
|
||||
*
|
||||
* @param path
|
||||
* @param cleanUp
|
||||
*/
|
||||
private Path(String path, boolean cleanUp) {
|
||||
this.path = cleanUp ? cleanUp(path) : path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given {@link String} to the current {@link Path}.
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public Path slash(String path) {
|
||||
return new Path(this.path + cleanUp(path), false);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return path.hashCode();
|
||||
}
|
||||
|
||||
private static String cleanUp(String path) {
|
||||
|
||||
if (!StringUtils.hasText(path)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String trimmed = path.trim().replaceAll(" ", "");
|
||||
trimmed = SLASH + trimmed.substring(getFirstNoneSlashIndex(trimmed));
|
||||
|
||||
while (trimmed.endsWith("/")) {
|
||||
trimmed = trimmed.substring(0, trimmed.length() - 1);
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(obj instanceof Path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Path that = (Path) obj;
|
||||
return this.path.equals(that.path);
|
||||
}
|
||||
|
||||
private static int getFirstNoneSlashIndex(String input) {
|
||||
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
if (input.charAt(i) != '/') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return input.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PathUnitTests {
|
||||
|
||||
@Test
|
||||
public void combinesSimplePaths() {
|
||||
|
||||
Path builder = new Path("foo").slash("bar");
|
||||
assertThat(builder.toString(), is("/foo/bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesLeadingAndTrailingSlashes() {
|
||||
|
||||
Path builder = new Path("foo/").slash("/bar").slash("//foobar///");
|
||||
assertThat(builder.toString(), is("/foo/bar/foobar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removesWhitespace() {
|
||||
|
||||
Path builder = new Path("foo/ ").slash("/ b a r").slash(" //foobar/// ");
|
||||
assertThat(builder.toString(), is("/foo/bar/foobar"));
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
class CollectionResourceMappingBuilder implements InternalMappingBuilder {
|
||||
|
||||
private final CollectionResourceMapping mapping;
|
||||
|
||||
public CollectionResourceMappingBuilder(CollectionResourceMapping mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withCollectionRel(java.lang.String)
|
||||
*/
|
||||
public CollectionResourceMappingBuilder withCollectionRel(String rel) {
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(rel != null ? rel
|
||||
: mapping.getRel(), mapping.getSingleResourceRel(), mapping.getPath(), mapping.isExported());
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withSingleRel(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMappingBuilder withSingleRel(String rel) {
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(mapping.getRel(),
|
||||
rel != null ? rel : mapping.getSingleResourceRel(), mapping.getPath(), mapping.isExported());
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withPath(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMappingBuilder withPath(String path) {
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(mapping.getRel(),
|
||||
mapping.getSingleResourceRel(), path != null ? path : mapping.getPath(), mapping.isExported());
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#withExposed(java.lang.Boolean)
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMappingBuilder withExposed(Boolean exported) {
|
||||
|
||||
SimpleCollectionResourceMapping newMapping = new SimpleCollectionResourceMapping(mapping.getRel(),
|
||||
mapping.getSingleResourceRel(), mapping.getPath(), exported != null ? exported : mapping.isExported());
|
||||
|
||||
return new CollectionResourceMappingBuilder(newMapping);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#merge(org.springframework.data.rest.repository.mapping.CollectionResourceMapping)
|
||||
*/
|
||||
@Override
|
||||
public InternalMappingBuilder merge(CollectionResourceMapping mapping) {
|
||||
|
||||
if (mapping == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return withCollectionRel(mapping.getRel()). //
|
||||
withSingleRel(mapping.getSingleResourceRel()). //
|
||||
withPath(mapping.getPath()). //
|
||||
withExposed(mapping.isExported());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.InternalMappingBuilder#getMapping()
|
||||
*/
|
||||
@Override
|
||||
public CollectionResourceMapping getMapping() {
|
||||
|
||||
Assert.hasText(mapping.getRel(), "Rel must not be null or empty!");
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the exported
|
||||
*/
|
||||
public Boolean isExported() {
|
||||
return mapping.isExported();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface InternalMappingBuilder extends MappingBuilder {
|
||||
|
||||
InternalMappingBuilder merge(CollectionResourceMapping mapping);
|
||||
|
||||
CollectionResourceMapping getMapping();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
/**
|
||||
* SPI to allow users to register
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface MappingBuilder {
|
||||
|
||||
MappingBuilder withCollectionRel(String rel);
|
||||
|
||||
MappingBuilder withSingleRel(String rel);
|
||||
|
||||
MappingBuilder withPath(String path);
|
||||
|
||||
MappingBuilder withExposed(Boolean exposed);
|
||||
|
||||
}
|
||||
@@ -15,11 +15,14 @@
|
||||
*/
|
||||
package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
import org.springframework.data.repository.support.Repositories;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -29,7 +32,7 @@ public class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
|
||||
private final Repositories repositories;
|
||||
private final CollectionResourceMapping mapping;
|
||||
private final ResourceMetadataProvider provider;
|
||||
private final ResourceMappings provider;
|
||||
private final RepositoryInformation repositoryInterface;
|
||||
|
||||
/**
|
||||
@@ -38,7 +41,7 @@ public class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
* @param provider must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryAwareResourceInformation(Repositories repositories, CollectionResourceMapping mapping,
|
||||
ResourceMetadataProvider provider, RepositoryInformation repositoryInterface) {
|
||||
ResourceMappings provider, RepositoryInformation repositoryInterface) {
|
||||
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(mapping, "ResourceMapping must not be null!");
|
||||
@@ -113,7 +116,17 @@ public class RepositoryAwareResourceInformation implements ResourceMetadata {
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getPath()
|
||||
*/
|
||||
@Override
|
||||
public String getPath() {
|
||||
public Path getPath() {
|
||||
return mapping.getPath();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMetadata#getSearchResourceMappings()
|
||||
*/
|
||||
@Override
|
||||
public Map<String, ResourceMapping> getSearchResourceMappings() {
|
||||
return provider.getSearchResourceMappings(repositoryInterface.getRepositoryInterface());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.support.RepositoriesUtils;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link CollectionResourceMapping} to be built from repository interfaces. Will inspect {@link RestResource}
|
||||
* annotations on the repository interface but fall back to the mapping information of the managed domain type for
|
||||
* defaults.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryCollectionResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
private final RestResource annotation;
|
||||
private final CollectionResourceMapping domainTypeMapping;
|
||||
|
||||
public RepositoryCollectionResourceMapping(Class<?> repositoryType) {
|
||||
this(repositoryType, new EvoInflectorRelProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link RepositoryCollectionResourceMapping} for the given repository using the given
|
||||
* {@link RelProvider}.
|
||||
*
|
||||
* @param repositoryType must not be {@literal null}.
|
||||
* @param relProvider must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryCollectionResourceMapping(Class<?> repositoryType, RelProvider relProvider) {
|
||||
|
||||
Assert.isTrue(RepositoriesUtils.isRepositoryInterface(repositoryType), "Given type is not a repository!");
|
||||
Assert.notNull(relProvider, "RelProvider must not be null!");
|
||||
|
||||
this.annotation = AnnotationUtils.findAnnotation(repositoryType, RestResource.class);
|
||||
this.domainTypeMapping = new TypeBasedCollectionResourceMapping(RepositoriesUtils.getDomainType(repositoryType),
|
||||
relProvider);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#getPath()
|
||||
*/
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
return annotation == null || !StringUtils.hasText(annotation.path()) ? domainTypeMapping.getPath()
|
||||
: new Path(annotation.path());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#getRel()
|
||||
*/
|
||||
@Override
|
||||
public String getRel() {
|
||||
return annotation == null || !StringUtils.hasText(annotation.rel()) ? domainTypeMapping.getRel() : annotation.rel();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
return domainTypeMapping.getSingleResourceRel();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
return annotation == null ? domainTypeMapping.isExported() : annotation.exported();
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ package org.springframework.data.rest.repository.mapping;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link RepositoryMethodResourceMapping} created from a {@link Method}.
|
||||
@@ -29,20 +31,24 @@ public class RepositoryMethodResourceMapping implements ResourceMapping {
|
||||
|
||||
private final boolean isExported;
|
||||
private final String rel;
|
||||
private final String path;
|
||||
private final Path path;
|
||||
|
||||
/**
|
||||
* Creates a new {@link RepositoryMethodResourceMapping} for the given {@link Method}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
*/
|
||||
public RepositoryMethodResourceMapping(Method method) {
|
||||
public RepositoryMethodResourceMapping(Method method, ResourceMapping resourceMapping) {
|
||||
|
||||
RestResource annotation = AnnotationUtils.findAnnotation(method, RestResource.class);
|
||||
|
||||
this.isExported = annotation != null ? annotation.exported() : true;
|
||||
this.rel = annotation != null ? annotation.rel() : method.getName();
|
||||
this.path = annotation != null ? annotation.path() : method.getName();
|
||||
|
||||
Path resourcePath = resourceMapping.getPath();
|
||||
String toAppend = annotation == null || !StringUtils.hasText(annotation.path()) ? method.getName() : annotation
|
||||
.path();
|
||||
this.path = resourcePath.slash(toAppend);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -68,7 +74,7 @@ public class RepositoryMethodResourceMapping implements ResourceMapping {
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#getPath()
|
||||
*/
|
||||
@Override
|
||||
public String getPath() {
|
||||
public Path getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
import org.springframework.data.rest.core.Path;
|
||||
|
||||
/**
|
||||
* Mapping information for components to be exported as REST resources.
|
||||
*
|
||||
@@ -22,24 +24,6 @@ package org.springframework.data.rest.repository.mapping;
|
||||
*/
|
||||
public interface ResourceMapping {
|
||||
|
||||
public static ResourceMapping NO_MAPPING = new ResourceMapping() {
|
||||
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the component shall be exported at all.
|
||||
*
|
||||
@@ -59,5 +43,5 @@ public interface ResourceMapping {
|
||||
*
|
||||
* @return will never be {@literal null}.
|
||||
*/
|
||||
String getPath();
|
||||
Path getPath();
|
||||
}
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.support.RepositoriesUtils;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ResourceMappingFactory {
|
||||
|
||||
private final RelProvider relProvider;
|
||||
|
||||
public ResourceMappingFactory(RelProvider relProvider) {
|
||||
this.relProvider = relProvider;
|
||||
}
|
||||
|
||||
public CollectionResourceMapping getMappingForType(Class<?> type) {
|
||||
return getMappingForType(type, new CollectionResourceMapping[0]);
|
||||
}
|
||||
|
||||
public CollectionResourceMapping getMappingForType(Class<?> type, CollectionResourceMapping... manualMapping) {
|
||||
|
||||
Class<?> typeToInspect = getTypeToInspect(type);
|
||||
|
||||
InternalMappingBuilder mapping = getBaseMetadata(typeToInspect). //
|
||||
merge(discoverConfig(typeToInspect));
|
||||
|
||||
if (type != typeToInspect) {
|
||||
mapping = mapping.merge(discoverConfig(type));
|
||||
}
|
||||
|
||||
for (CollectionResourceMapping externalMapping : manualMapping) {
|
||||
mapping = mapping.merge(externalMapping);
|
||||
}
|
||||
|
||||
return mapping.getMapping();
|
||||
}
|
||||
|
||||
private static Class<?> getTypeToInspect(Class<?> type) {
|
||||
|
||||
if (!RepositoriesUtils.isRepositoryInterface(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
return RepositoriesUtils.getDomainType(type);
|
||||
}
|
||||
|
||||
private InternalMappingBuilder getBaseMetadata(Class<?> domainType) {
|
||||
|
||||
String path = StringUtils.uncapitalize(domainType.getSimpleName());
|
||||
String defaultCollectionRel = relProvider.getCollectionResourceRelFor(domainType);
|
||||
String defaultSingleRel = relProvider.getSingleResourceRelFor(domainType);
|
||||
|
||||
CollectionResourceMapping mapping = new SimpleCollectionResourceMapping(defaultCollectionRel, defaultSingleRel,
|
||||
path, true);
|
||||
|
||||
return new CollectionResourceMappingBuilder(mapping);
|
||||
}
|
||||
|
||||
private static final CollectionResourceMapping discoverConfig(Class<?> type) {
|
||||
|
||||
RestResource resource = AnnotationUtils.findAnnotation(type, RestResource.class);
|
||||
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AnnotationResourceMapping(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link CollectionResourceMapping} based on an {@link RestResource} annotation.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private static class AnnotationResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
private final RestResource annotation;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationResourceMapping} for the given {@link RestResource}.
|
||||
*
|
||||
* @param annotation must not be {@literal null}.
|
||||
*/
|
||||
public AnnotationResourceMapping(RestResource annotation) {
|
||||
Assert.notNull(annotation, "Annotation must not be null!");
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
return annotation.exported();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getCollectionRel()
|
||||
*/
|
||||
@Override
|
||||
public String getRel() {
|
||||
return StringUtils.hasText(annotation.rel()) ? annotation.rel() : null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
|
||||
String rel = getRel();
|
||||
return rel == null ? null : String.format("%s.%s", rel, rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getPath()
|
||||
*/
|
||||
@Override
|
||||
public String getPath() {
|
||||
return StringUtils.hasText(annotation.path()) ? annotation.path() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,11 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ResourceMappings implements ResourceMetadataProvider, Iterable<ResourceMetadata> {
|
||||
public class ResourceMappings implements Iterable<ResourceMetadata> {
|
||||
|
||||
|
||||
private final RepositoryRestConfiguration config;
|
||||
private final ResourceMappingFactory factory;
|
||||
private final Repositories repositories;
|
||||
private final RelProvider relProvider;
|
||||
|
||||
private final Map<Class<?>, ResourceMetadata> cache = new HashMap<Class<?>, ResourceMetadata>();
|
||||
private final Map<Class<?>, Map<String, ResourceMapping>> searchCache = new HashMap<Class<?>, Map<String, ResourceMapping>>();
|
||||
@@ -66,13 +65,11 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
*/
|
||||
public ResourceMappings(RepositoryRestConfiguration config, Repositories repositories, RelProvider relProvider) {
|
||||
|
||||
Assert.notNull(config, "RepositoryRestConfiguration must not be null!");
|
||||
Assert.notNull(repositories, "Repositories must not be null!");
|
||||
Assert.notNull(relProvider, "RelProvider must not be null!");
|
||||
|
||||
this.config = config;
|
||||
this.repositories = repositories;
|
||||
this.factory = new ResourceMappingFactory(relProvider);
|
||||
this.relProvider = relProvider;
|
||||
|
||||
this.populateCache(repositories);
|
||||
}
|
||||
@@ -96,8 +93,7 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(type);
|
||||
Class<?> repositoryInterface = repositoryInformation.getRepositoryInterface();
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(repositoryInterface, fromConfig(type),
|
||||
fromConfig(repositoryInterface));
|
||||
CollectionResourceMapping mapping = new RepositoryCollectionResourceMapping(repositoryInterface, relProvider);
|
||||
|
||||
RepositoryAwareResourceInformation information = new RepositoryAwareResourceInformation(repositories, mapping,
|
||||
this, repositoryInformation);
|
||||
@@ -125,9 +121,11 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
Class<?> domainType = RepositoriesUtils.getDomainType(type);
|
||||
RepositoryInformation repositoryInformation = repositories.getRepositoryInformationFor(domainType);
|
||||
Map<String, ResourceMapping> mappings = new HashMap<String, ResourceMapping>();
|
||||
ResourceMetadata repositoryMapping = getMappingFor(repositoryInformation.getRepositoryInterface());
|
||||
|
||||
for (Method queryMethod : repositoryInformation.getQueryMethods()) {
|
||||
mappings.put(queryMethod.getName(), new RepositoryMethodResourceMapping(queryMethod));
|
||||
mappings.put(queryMethod.getName(), new RepositoryMethodResourceMapping(queryMethod,
|
||||
repositoryMapping));
|
||||
}
|
||||
|
||||
searchCache.put(type, mappings);
|
||||
@@ -177,8 +175,7 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMetadataProvider#getMappingFor(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public ResourceMapping getMappingFor(PersistentProperty<?> property) {
|
||||
ResourceMapping getMappingFor(PersistentProperty<?> property) {
|
||||
return getMappingFor(property.getActualType());
|
||||
}
|
||||
|
||||
@@ -186,7 +183,6 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMetadataProvider#hasMappingFor(org.springframework.data.mapping.PersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public boolean isMapped(PersistentProperty<?> property) {
|
||||
|
||||
ResourceMapping metadata = getMappingFor(property);
|
||||
@@ -201,15 +197,4 @@ public class ResourceMappings implements ResourceMetadataProvider, Iterable<Reso
|
||||
public Iterator<ResourceMetadata> iterator() {
|
||||
return cache.values().iterator();
|
||||
}
|
||||
|
||||
private CollectionResourceMapping fromConfig(Class<?> domainType) {
|
||||
|
||||
org.springframework.data.rest.config.ResourceMapping mapping = config.getResourceMappingForDomainType(domainType);
|
||||
|
||||
if (mapping == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SimpleCollectionResourceMapping(mapping.getRel(), null, mapping.getPath(), mapping.isExported());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.rest.repository.mapping;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ResourceMetadata extends CollectionResourceMapping, ResourceMetadataProvider {
|
||||
public interface ResourceMetadata extends CollectionResourceMapping {
|
||||
|
||||
boolean isManaged(PersistentProperty<?> property);
|
||||
|
||||
boolean isMapped(PersistentProperty<?> property);
|
||||
|
||||
ResourceMapping getMappingFor(PersistentProperty<?> property);
|
||||
|
||||
Map<String, ResourceMapping> getSearchResourceMappings();
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ResourceMetadataProvider {
|
||||
|
||||
boolean isMapped(PersistentProperty<?> property);
|
||||
|
||||
ResourceMapping getMappingFor(PersistentProperty<?> property);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
public class SimpleCollectionResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
private final String collectionRel;
|
||||
private final String singleRel;
|
||||
private final String path;
|
||||
private final Boolean exported;
|
||||
|
||||
public SimpleCollectionResourceMapping(String relsAndPath) {
|
||||
this(relsAndPath, relsAndPath, relsAndPath, true);
|
||||
}
|
||||
|
||||
public SimpleCollectionResourceMapping(String collectionRel, String singleRel, String path, Boolean exported) {
|
||||
|
||||
this.collectionRel = collectionRel;
|
||||
this.singleRel = singleRel;
|
||||
this.path = path;
|
||||
this.exported = exported;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getCollectionRel()
|
||||
*/
|
||||
public String getRel() {
|
||||
return collectionRel;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
public String getSingleResourceRel() {
|
||||
return singleRel;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getPath()
|
||||
*/
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the exported
|
||||
*/
|
||||
public Boolean isExported() {
|
||||
return exported;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link CollectionResourceMapping} based on a type. Will derive default relation types and pathes from the type but
|
||||
* inspect it for {@link RestResource} annotations for customization.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class TypeBasedCollectionResourceMapping implements CollectionResourceMapping {
|
||||
|
||||
private final Class<?> type;
|
||||
private final RestResource annotation;
|
||||
private final RelProvider relProvider;
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeBasedCollectionResourceMapping} using the given type.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
*/
|
||||
public TypeBasedCollectionResourceMapping(Class<?> type) {
|
||||
this(type, new EvoInflectorRelProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypeBasedCollectionResourceMapping} using the given type and {@link RelProvider}.
|
||||
*
|
||||
* @param type must not be {@literal null}.
|
||||
* @param relProvider must not be {@literal null}.
|
||||
*/
|
||||
public TypeBasedCollectionResourceMapping(Class<?> type, RelProvider relProvider) {
|
||||
|
||||
Assert.notNull(type, "Type must not be null!");
|
||||
Assert.notNull(relProvider, "RelProvider must not be null!");
|
||||
|
||||
this.type = type;
|
||||
this.relProvider = relProvider;
|
||||
this.annotation = AnnotationUtils.findAnnotation(type, RestResource.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#getPath()
|
||||
*/
|
||||
@Override
|
||||
public Path getPath() {
|
||||
|
||||
String path = annotation == null ? null : annotation.path().trim();
|
||||
path = StringUtils.hasText(path) ? path : StringUtils.uncapitalize(type.getSimpleName());
|
||||
return new Path(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#isExported()
|
||||
*/
|
||||
@Override
|
||||
public Boolean isExported() {
|
||||
return annotation == null ? true : annotation.exported();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.ResourceMapping#getRel()
|
||||
*/
|
||||
@Override
|
||||
public String getRel() {
|
||||
|
||||
if (annotation == null || !StringUtils.hasText(annotation.rel())) {
|
||||
return relProvider.getCollectionResourceRelFor(type);
|
||||
}
|
||||
|
||||
return annotation.rel();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.rest.repository.mapping.CollectionResourceMapping#getSingleResourceRel()
|
||||
*/
|
||||
@Override
|
||||
public String getSingleResourceRel() {
|
||||
return relProvider.getSingleResourceRelFor(type);
|
||||
}
|
||||
}
|
||||
@@ -25,13 +25,15 @@ import org.junit.Test;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.domain.jpa.AnnotatedPersonRepository;
|
||||
import org.springframework.data.rest.repository.domain.jpa.Person;
|
||||
import org.springframework.data.rest.repository.domain.jpa.PlainPersonRepository;
|
||||
import org.springframework.data.rest.repository.mapping.RepositoryCollectionResourceMapping;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMapping;
|
||||
import org.springframework.data.rest.repository.mapping.ResourceMappingFactory;
|
||||
import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
import org.springframework.hateoas.RelProvider;
|
||||
import org.springframework.hateoas.core.EvoInflectorRelProvider;
|
||||
|
||||
/**
|
||||
* Ensure the {@link ResourceMapping} components convey the correct information.
|
||||
@@ -41,25 +43,26 @@ import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ResourceMappingUnitTests {
|
||||
|
||||
ResourceMappingFactory factory = new ResourceMappingFactory(new SimpleRelProvider());
|
||||
RelProvider relProvider = new EvoInflectorRelProvider();
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldDetectDefaultRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = factory.getMappingForType(PlainPersonRepository.class);
|
||||
ResourceMapping newMapping = new RepositoryCollectionResourceMapping(PlainPersonRepository.class, relProvider);
|
||||
|
||||
assertThat(newMapping.getRel(), is("person"));
|
||||
assertThat(newMapping.getPath(), is("person"));
|
||||
assertThat(newMapping.getRel(), is("persons"));
|
||||
assertThat(newMapping.getPath(), is(new Path("person")));
|
||||
assertThat(newMapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDetectAnnotatedRelAndPath() throws Exception {
|
||||
|
||||
ResourceMapping newMapping = factory.getMappingForType(AnnotatedPersonRepository.class);
|
||||
ResourceMapping newMapping = new RepositoryCollectionResourceMapping(AnnotatedPersonRepository.class, relProvider);
|
||||
|
||||
assertThat(newMapping.getRel(), is("people"));
|
||||
assertThat(newMapping.getPath(), is("person"));
|
||||
assertThat(newMapping.getPath(), is(new Path("person")));
|
||||
assertThat(newMapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryAwareResourceMappingFactoryUnitTests {
|
||||
|
||||
ResourceMappingFactory factory = new ResourceMappingFactory(new SimpleRelProvider());
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(Person.class);
|
||||
assertThat(mapping.getPath(), is("person"));
|
||||
assertThat(mapping.getRel(), is("person"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("person.person"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void honorsAnnotatedMapping() {
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(AnnotatedPerson.class);
|
||||
assertThat(mapping.getPath(), is("bar"));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
}
|
||||
|
||||
@RestResource(path = "bar", rel = "foo", exported = false)
|
||||
static class AnnotatedPerson {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,70 +20,59 @@ import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
import org.springframework.data.rest.repository.support.SimpleRelProvider;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link RepositoryCollectionResourceMapping}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ResourceMappingFactoryUnitTests {
|
||||
|
||||
ResourceMappingFactory factory = new ResourceMappingFactory(new SimpleRelProvider());
|
||||
public class RepositoryCollectionResourceMappingUnitTests {
|
||||
|
||||
@Test
|
||||
public void foo() {
|
||||
public void buildsDefaultMappingForRepository() {
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(Person.class);
|
||||
assertThat(mapping.getPath(), is("person"));
|
||||
assertThat(mapping.getRel(), is("person"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("person.person"));
|
||||
}
|
||||
CollectionResourceMapping mapping = new RepositoryCollectionResourceMapping(PersonRepository.class);
|
||||
|
||||
@Test
|
||||
public void honorsAnnotatedMapping() {
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(AnnotatedPerson.class);
|
||||
assertThat(mapping.getPath(), is("bar"));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
assertThat(mapping.getPath(), is(new Path("person")));
|
||||
assertThat(mapping.getRel(), is("persons"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("person"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void honorsAnnotatedsMapping() {
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(PersonRepository.class);
|
||||
assertThat(mapping.getPath(), is("bar"));
|
||||
CollectionResourceMapping mapping = new RepositoryCollectionResourceMapping(AnnotatedPersonRepository.class);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("bar")));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("annotatedPerson"));
|
||||
assertThat(mapping.isExported(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void repositoryAnnotationTrumpsDomainTypeMapping() {
|
||||
|
||||
CollectionResourceMapping mapping = factory.getMappingForType(AnnotatedAnnotatedPersonRepository.class);
|
||||
assertThat(mapping.getPath(), is("trumpsAll"));
|
||||
CollectionResourceMapping mapping = new RepositoryCollectionResourceMapping(
|
||||
AnnotatedAnnotatedPersonRepository.class);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("/trumpsAll")));
|
||||
assertThat(mapping.getRel(), is("foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("foo.foo"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("annotatedPerson"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
static class Person {
|
||||
|
||||
}
|
||||
static class Person {}
|
||||
|
||||
@RestResource(path = "bar", rel = "foo", exported = false)
|
||||
static class AnnotatedPerson {
|
||||
static class AnnotatedPerson {}
|
||||
|
||||
}
|
||||
interface PersonRepository extends Repository<Person, Long> {}
|
||||
|
||||
interface PersonRepository extends Repository<AnnotatedPerson, Long> {
|
||||
|
||||
}
|
||||
interface AnnotatedPersonRepository extends Repository<AnnotatedPerson, Long> {}
|
||||
|
||||
@RestResource(path = "trumpsAll")
|
||||
interface AnnotatedAnnotatedPersonRepository extends Repository<AnnotatedPerson, Long> {
|
||||
|
||||
}
|
||||
interface AnnotatedAnnotatedPersonRepository extends Repository<AnnotatedPerson, Long> {}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class RepositoryMethodResourceMappingUnitTests {
|
||||
|
||||
RepositoryCollectionResourceMapping resourceMapping = new RepositoryCollectionResourceMapping(
|
||||
PersonRepository.class);
|
||||
|
||||
@Test
|
||||
public void foo() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLastname", String.class);
|
||||
ResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("person/findByLastname")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesConfiguredNameWithLeadingSlash() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByFirstname", String.class);
|
||||
ResourceMapping mapping = new RepositoryMethodResourceMapping(method, resourceMapping);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("person/bar")));
|
||||
}
|
||||
|
||||
static class Person {}
|
||||
|
||||
interface PersonRepository extends Repository<Person, Long> {
|
||||
|
||||
Iterable<Person> findByLastname(String lastname);
|
||||
|
||||
@RestResource(path = "/bar")
|
||||
Iterable<Person> findByFirstname(String firstname);
|
||||
|
||||
@RestResource(path = "foo")
|
||||
Iterable<Person> findByEmailAddress(String email);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.repository.mapping;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.rest.core.Path;
|
||||
import org.springframework.data.rest.repository.annotation.RestResource;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link TypeBasedCollectionResourceMapping}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class TypeBasedCollectionResourceMappingUnitTest {
|
||||
|
||||
@Test
|
||||
public void defaultsMappingsByType() {
|
||||
|
||||
CollectionResourceMapping mapping = new TypeBasedCollectionResourceMapping(Sample.class);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("sample")));
|
||||
assertThat(mapping.getRel(), is("samples"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("sample"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesCustomizedRel() {
|
||||
|
||||
CollectionResourceMapping mapping = new TypeBasedCollectionResourceMapping(CustomizedSample.class);
|
||||
|
||||
assertThat(mapping.getPath(), is(new Path("customizedSample")));
|
||||
assertThat(mapping.getRel(), is("myRel"));
|
||||
assertThat(mapping.getSingleResourceRel(), is("customizedSample"));
|
||||
assertThat(mapping.isExported(), is(true));
|
||||
}
|
||||
|
||||
class Sample {
|
||||
|
||||
}
|
||||
|
||||
@RestResource(rel = "myRel")
|
||||
class CustomizedSample {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class RepositoryLinkBuilder extends LinkBuilderSupport<RepositoryLinkBuil
|
||||
|
||||
UriComponentsBuilder builder = baseUri != null ? UriComponentsBuilder.fromUri(baseUri) : ControllerLinkBuilder
|
||||
.linkTo(RepositoryController.class).toUriComponentsBuilder();
|
||||
return builder.path(metadata.getPath());
|
||||
return builder.path(metadata.getPath().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -127,7 +127,8 @@ public abstract class AbstractWebIntegrationTests {
|
||||
@Override
|
||||
public void match(MvcResult result) throws Exception {
|
||||
String s = result.getResponse().getContentAsString();
|
||||
assertThat(links.findLinkWithRel(rel, s), notNullValue());
|
||||
assertThat("Expected to find link with rel " + rel + " but found none in " + s, links.findLinkWithRel(rel, s),
|
||||
notNullValue());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -68,10 +68,10 @@ public class PersistentEntitySerializationTests {
|
||||
|
||||
String s = writer.toString();
|
||||
|
||||
Link fatherLink = linkDiscoverer.findLinkWithRel("people.people.father", s);
|
||||
Link fatherLink = linkDiscoverer.findLinkWithRel("person.father", s);
|
||||
assertThat(fatherLink.getHref(), endsWith(new UriTemplate("/{id}/father").expand(person.getId()).toString()));
|
||||
|
||||
Link siblingLink = linkDiscoverer.findLinkWithRel("people.people.siblings", s);
|
||||
Link siblingLink = linkDiscoverer.findLinkWithRel("person.siblings", s);
|
||||
assertThat(siblingLink.getHref(), endsWith(new UriTemplate("/{id}/siblings").expand(person.getId()).toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,13 +61,13 @@ public class MongoWebTests extends AbstractWebIntegrationTests {
|
||||
*/
|
||||
@Override
|
||||
protected Iterable<String> expectedRootLinkRels() {
|
||||
return Arrays.asList("profile");
|
||||
return Arrays.asList("profiles");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void foo() throws Exception {
|
||||
|
||||
Link profileLink = discoverUnique("profile");
|
||||
Link profileLink = discoverUnique("profiles");
|
||||
follow(profileLink).andExpect(jsonPath("$.content").value(hasSize(2)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user