diff --git a/build.gradle b/build.gradle index efae90342..f876aa5a5 100644 --- a/build.gradle +++ b/build.gradle @@ -193,7 +193,7 @@ project("spring-data-rest-repository") { compile("javax.validation:validation-api:1.0.0.GA", optional) // Evo Inflector - runtime "org.atteo:evo-inflector:${evoVersion}" + compile "org.atteo:evo-inflector:${evoVersion}" // Testing testCompile "org.hsqldb:hsqldb:$hsqldbVersion" diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/EvoInflectorTypeBasedCollectionResourceMapping.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/EvoInflectorTypeBasedCollectionResourceMapping.java new file mode 100644 index 000000000..9896e9df6 --- /dev/null +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/EvoInflectorTypeBasedCollectionResourceMapping.java @@ -0,0 +1,47 @@ +/* + * 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.atteo.evo.inflector.English; +import org.springframework.hateoas.RelProvider; + +/** + * {@link TypeBasedCollectionResourceMapping} extension to use Evo Inflector to pluralize the simple class name by as + * default path. + * + * @author Oliver Gierke + */ +class EvoInflectorTypeBasedCollectionResourceMapping extends TypeBasedCollectionResourceMapping { + + /** + * Creates a new {@link EvoInflectorTypeBasedCollectionResourceMapping} for the given type and {@link RelProvider}. + * + * @param type must not be {@literal null}. + * @param relProvider must not be {@literal null}. + */ + public EvoInflectorTypeBasedCollectionResourceMapping(Class type, RelProvider relProvider) { + super(type, relProvider); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.rest.repository.mapping.TypeBasedCollectionResourceMapping#getDefaultPathFor(java.lang.Class) + */ + @Override + protected String getDefaultPathFor(Class type) { + return English.plural(super.getDefaultPathFor(type)); + } +} 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 0fc39d789..46af5e4f9 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 @@ -24,6 +24,7 @@ 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.ClassUtils; import org.springframework.util.StringUtils; /** @@ -35,6 +36,8 @@ import org.springframework.util.StringUtils; */ class RepositoryCollectionResourceMapping implements CollectionResourceMapping { + private final boolean EVO_INFLECTOR_IS_PRESENT = ClassUtils.isPresent("org.atteo.evo.inflector.English", null); + private final RestResource annotation; private final CollectionResourceMapping domainTypeMapping; private final boolean repositoryIsExportCandidate; @@ -56,9 +59,11 @@ class RepositoryCollectionResourceMapping implements CollectionResourceMapping { Assert.notNull(relProvider, "RelProvider must not be null!"); this.annotation = AnnotationUtils.findAnnotation(repositoryType, RestResource.class); - this.domainTypeMapping = new TypeBasedCollectionResourceMapping(RepositoriesUtils.getDomainType(repositoryType), - relProvider); this.repositoryIsExportCandidate = Modifier.isPublic(repositoryType.getModifiers()); + + Class domainType = RepositoriesUtils.getDomainType(repositoryType); + this.domainTypeMapping = EVO_INFLECTOR_IS_PRESENT ? new EvoInflectorTypeBasedCollectionResourceMapping(domainType, + relProvider) : new TypeBasedCollectionResourceMapping(domainType, relProvider); } /* diff --git a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/TypeBasedCollectionResourceMapping.java b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/TypeBasedCollectionResourceMapping.java index 9f901fc73..36946b29a 100644 --- a/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/TypeBasedCollectionResourceMapping.java +++ b/spring-data-rest-repository/src/main/java/org/springframework/data/rest/repository/mapping/TypeBasedCollectionResourceMapping.java @@ -70,7 +70,7 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping { public Path getPath() { String path = annotation == null ? null : annotation.path().trim(); - path = StringUtils.hasText(path) ? path : StringUtils.uncapitalize(type.getSimpleName()); + path = StringUtils.hasText(path) ? path : getDefaultPathFor(type); return new Path(path); } @@ -105,4 +105,14 @@ class TypeBasedCollectionResourceMapping implements CollectionResourceMapping { public String getSingleResourceRel() { return relProvider.getSingleResourceRelFor(type); } + + /** + * Returns the default path to be used if the path is not configured manually. + * + * @param type must not be {@literal null}. + * @return + */ + protected String getDefaultPathFor(Class type) { + return StringUtils.uncapitalize(type.getSimpleName()); + } }