Issue
Is it possible to specify projection
when calling data repository method directly? Here's repository code - note I would not like to expose it via REST, instead I would like to be able to call it from a service or controller:
@RepositoryRestResource(exported = false)
public interface UsersRepository extends PagingAndSortingRepository<User, Long> {
@Query(value = "SELECT u FROM User u WHERE ....")
public Page<User> findEmployeeUsers(Pageable p);
}
Then in a controller I do this:
@PreAuthorize(value = "hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/users/employee")
public Page<User> listEmployees(Pageable pageable) {
return usersRepository.findEmployeeUsers(pageable);
}
Is there any way to specify projection
for findEmployeeUsers
method when it is called directly like above?
I realise that the code above might look odd for someone... it would be possible to expose the repository via REST and put the @PreAuthorize
thing in the repository. Thought controller is the more right place to do security checks - it is more natural as well as simpler to test.
So, can projection
thing be somehow passed into a repository method called directly?
Solution
No it's not, especially as projections are usually applied to the result of a query execution on a case by case basis. Thus they're currently designed to be selectively applied to domain types.
As of the latest Spring Data Fowler release train GA release the projection infrastructure can be used programmatically in Spring MVC controllers. Simply declare a Spring bean for SpelAwareProxyProjectionFactory
:
@Configuration
class SomeConfig {
@Bean
public SpelAwareProxyProjectionFactory projectionFactory() {
return new SpelAwareProxyProjectionFactory();
}
}
Then inject it into your controller and use it:
@Controller
class SampleController {
private final ProjectionFactory projectionFactory;
@Autowired
public SampleController(ProjectionFactory projectionFactory) {
this.projectionFactory = projectionFactory;
}
@PreAuthorize(value = "hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/users/employee")
public Page<?> listEmployees(Pageable pageable) {
return usersRepository.findEmployeeUsers(pageable).//
map(user -> projectionFactory.createProjection(Projection.class, user);
}
}
See how as of the latest release Page
has a map(…)
method that can be used to transform the page content on the fly. We use a JDK 8 lambda to provide a conversion step using the ProjectionFactory
.
Answered By - Oliver Drotbohm
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)