Is it possible to create read-only repositories using Spring Data?
I have some entities linked to views and some child entities for which I would like to provide a r
As far as we can see in documentation, this is possible by implementing org.springframework.data.repository.Repository.
To expand on Oliver Gierke's answer, in the more recent versions of Spring Data you will need the @NoRepositoryBean annotation on your ReadOnlyRepository (parent interface) to prevent application start up errors:
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
@NoRepositoryBean
public interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
List<T> findAll();
}
This is for read-only PagingAndSortingRepository
package com.oracle.odc.data.catalog.service.core.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RestResource;
/**
* Extension of {@link PagingAndSortingRepository} but without modification capabilities
*
* @author XYZ
* @see Sort
* @see Pageable
* @see Page
*/
@NoRepositoryBean
public interface ReadOnlyPagingAndSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
@Override
@RestResource(exported=false)
<S extends T> S save(S entity);
@Override
@RestResource(exported=false)
<S extends T> Iterable<S> saveAll(Iterable<S> entities);
@Override
@RestResource(exported=false)
void deleteById(ID id);
@Override
@RestResource(exported=false)
void delete(T entity);
@Override
@RestResource(exported=false)
void deleteAll(Iterable<? extends T> entities);
@Override
@RestResource(exported=false)
void deleteAll();
}
If you try to POST or DELETE, you will get 405 (Method Not Allowed).
For me the following worked. Using Oliver's solution, I was getting error Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property findOne found for type
while starting up.
@NoRepositoryBean
public interface ReadOnlyRepository<T,ID> extends Repository<T, ID> {
Optional<T> findById(ID var1);
boolean existsById(ID var1);
Iterable<T> findAll();
Iterable<T> findAllById(Iterable<ID> var1);
long count();
}
Yes, the way to go is to add a handcrafted base repository. You usually use something like this:
public interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
Iterable<T> findAll();
}
You can now have you concrete repos extend that just defined one:
public interface PersonRepository extends ReadOnlyRepository<Person, Long> {
T findByEmailAddress(String emailAddress);
}
The crucial part defining the base repo is that the method declarations carry the very same signature as the methods declared in CrudRepository
if that's the case we can still route the calls into the implementation bean backing the repository proxy. I've written a more detailed blog post about that topic in the SpringSource blog.
Or if you want to make your own implementation or block this actions - you can do something like this (works withJava 8 and higher):
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.lang.NonNull;
import java.util.List;
@NoRepositoryBean
public interface ReadOnlyRepository<T, ID> extends JpaRepository<T, ID> {
@Override
@NonNull
default <S extends T> S save(@NonNull S entity) {
throw new RuntimeException("Action not allowed");
}
@Override
@NonNull
default <S extends T> List<S> saveAll(@NonNull Iterable<S> iterable) {
throw new RuntimeException("Action not allowed.");
}
@Override
@NonNull
default <S extends T> S saveAndFlush(@NonNull S s) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void delete(@NonNull T entity) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteAll() {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteAll(@NonNull Iterable<? extends T> entities) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteAllInBatch() {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteById(@NonNull ID id) {
throw new RuntimeException("Action not allowed.");
}
@Override
default void deleteInBatch(@NonNull Iterable<T> iterable) {
throw new RuntimeException("Action not allowed.");
}
}
Hope I help somebody (ノ^∇^)