Reputation: 303
Basing on https://spring.io/guides/gs/accessing-data-rest/ in the sample project https://github.com/jcoig/gs-accessing-data-rest) i have repository defined as follows:
@RepositoryRestResource
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(@Param("name") String name);
}
Such defined repository is available via http://localhost:8080/persons
and the response is:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons{?page,size,sort}",
"templated" : true
},
"search" : {
"href" : "http://localhost:8080/persons/search"
}
},
"_embedded" : {
"persons" : [ {
"firstName" : "John",
"lastName" : "Smith",
"_links" : {
"self" : {
"href" : "http://localhost:8080/persons/1"
}
}
} ]
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
I don't want to have persons
in the URL and I don't want to have persons
as the key in the returned JSON. Of Course I can define my repository as below:
@RepositoryRestResource(collectionResourceRel = "key", path = "path")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(@Param("name") String name);
}
but my question is how to change default Spring's behavior and got custom key and custom path provider (just as example to disable s
suffixes).
Upvotes: 1
Views: 3244
Reputation: 131
If the solution applying @Order(value = Ordered.HIGHEST_PRECEDENCE)
on the customized RelProvider
instance is not working the following workaround may help:
@Configuration
@Import(RepositoryRestMvcConfiguration.class)
public class RestMvcConfigurer extends RepositoryRestMvcConfiguration
{
...
@Override
public ResourceMappings resourceMappings()
{
final Repositories repositories = repositories();
final RepositoryRestConfiguration config = config();
return new RepositoryResourceMappings( config, repositories, new YourCustomRelProvider());
}
}
Further I had to exclude evo-inflector
from the classpath:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<exclusions>
<exclusion>
<groupId>org.atteo</groupId>
<artifactId>evo-inflector</artifactId>
</exclusion>
</exclusions>
</dependency>
Not really a nice solution, but it works for my setup.
Upvotes: 2
Reputation: 83171
Let's make sure what we're trying to achieve in the first place: Spring Data REST exposes two kinds of primary resources: collection resources and item resources. To be able to differentiate between the two we need two different relation names. So by default Spring Data REST uses the uncapitalized domain class name for the item resource rel and the Evo Inflector library to pluralize the item resource rel and use that as collection relation name (effectively what you informally described as adding the s suffix).
If you manually exclude the Evo Inflector library, Spring Data REST falls back to ${itemRel}List
for the collection relation, which first of all is more clunky than using properly pluralized names.
As you also discovered already, you can manually configure the names to be used for each repository. However, it's a very bad idea to configure the collection resource rel to be the item resource rel as this will prevent the clients from differentiating between the two resource types.
Assuming you've got this far reading and still want to deploy a custom strategy to globally alter the relation names for types you can implement a RelProvider
(see EvoInflectorRelProvider
or DefaultRelProvider
for implementation examples). If you register that implementation as Spring bean.
@Configuration
class MyConfig {
@Bean
YourCustomRelProvider customRelProvider() {
return new YourCustomRelProvider(…);
}
}
You might wanna experiment with the order (see @Order
or the Ordered
interface) of the implementation to make sure your custom provider is chosen in favor of the default ones registered.
Upvotes: 1