I have a Spring Data Rest webmvc application that I'd like to add some custom functionality to for batch operations.
I've created a controller, and blended it into the uri namespace, but I'd like for it to be able to accept URI's like the custom /search
queries do, rather than simply an ID.
I have tried registering a custom <String, Long>
converter (my entity has a Long
ID type, but that seems to get ignored. Is there any way to configure my controller such that it adopts that behavior from the auto-implemented SDR controllers?
Even if there is some sort of method I can call that will auto-resolve a URI to an entity, that would work just as well (as I can then simply accept a String
in my controller)
Here's where I'm at.
@Configuration
public class CustomWebConfiguration extends WebMvcConfigurationSupport {
//irrelevant code omitted
@Bean
public DomainClassConverter<?> domainClassConverter() {
DomainClassConverter<FormattingConversionService> dc = new DomainClassConverter<FormattingConversionService>(mvcConversionService());
return dc;
}
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(String.class, Long.class, testConverter());
}
@Bean
Converter<String, Long> testConverter() {
return new Converter<String, Long>() {
@Override
public Long convert(String source) {
//this code does _not_ get run at any point
if (source.indexOf('/') == -1) { return Long.parseLong(source); }
source = source.substring(source.lastIndexOf('/') + 1);
Long id = Long.parseLong(source);
return id;
}
};
}
}
SDR Config
@Configuration
@EnableHypermediaSupport(type = { HypermediaType.HAL })
public class CustomRestConfiguration extends RepositoryRestMvcConfiguration {
@Override
public RepositoryRestConfiguration config() {
RepositoryRestConfiguration config = super.config();
config.setBasePath("/api");
config.exposeIdsFor(ApplicationMembership.class);
return config;
}
}
And my (contrived) controller:
ApplicationType is one of my entities that are correctly managed by SDR/repository magic
@BasePathAwareController
@RepositoryRestController
@RequestMapping("applications/special")
public class ApplicationExtensionController {
@RequestMapping("a")
public ResponseEntity<?> reply(@RequestParam("type") ApplicationType type) {
return new ResponseEntity<String>(type.getIcon(), HttpStatus.OK);
}
}
I've looked around quite a bit but can't quite manage to make anything work. When I create a <String, ApplicationType>
converter that utilizes the repository, it also does not get called, as the DomainClassConverter just calls its underlying <String, Long>
converter (which obviously fails, as it cannot correctly parse out types/1
into a long.
Appreciate the help!
Forgot to mention
- Spring Data Rest 2.4.0
- Spring HATEOAS 0.19.0
- Spring 4.2.1
Using JPA repositories
As it turns out, I was on the right track with adding a converter, unfortunately I was doing it in the wrong configuration method.
I was able to get the desired functionality by moving my
testConverter()
bean to theRepositoryRestMvcConfiguration
extension config class and then addingAnd working as intended. I feel a bit silly now for throwing that in the wrong spot in the first place, but hopefully this will help someone else out!
I am posting an answer based on my last comment.
Apparently the logic you require -- autoconverting URI from
@RequestParam
to a repository-managed entity -- is implemented in a few private methods ofRepositorySearchController
(seeexecuteQueryMethod
andprepareUris
), so there's no easy way to get it in custom controllers.You can try creating your own argument resolver with Spring HATEOAS. Look into how
PersistentEntityResourceHandlerMethodArgumentResolver
resolver is implemented. It resolved an entity based on its@BackendId
.