I am using Spring DATA JPA and selected #Query annotation for creating queries (instead of using NamedQueries and Queries created from MethodName)
I have a data repository as below
public interface EventRepository extends CrudRepository<Event, Long> {
#Query("select e from Event e where e.name = :eventName)
public List<Event>findEventByName(String eventName );
}
Interface looks good and its enough as per Spring reference doc.
But I need a impl class because I need many other methods in addition to above.
I am facing 2 issues when I create EventRepositoryImpl java implementing EventRepository
Its asking to implement all the methods in EventRepository, findEventByName method is self contained in interface and why I need implement it again in Impl class?
Its asking to implement all the methods in CrudRepository, I know its per OOPS design, But there many methods
So, for these issues can I define my EventRepositoryImpl as abstract,
this seems to be working fine.
But do I need to worry about anything else, when Spring uses a abstract class as a bean.
or is there an elegant way to solve this issue.
Appreciate your help.
You do not have to implement all of these methods neither create an abstract class. Take a look into official documentation.
interface UserRepositoryCustom {
public void someCustomMethod(User user);
}
class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom {
// Declare query methods here
}
Related
We can write custom implementation of repository:
interface UserRepositoryCustom {
public void someCustomMethod(User user);
}
class UserRepositoryImpl implements UserRepositoryCustom {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
But what if I want customize only some methods? For example:
interface UserRepositoryCustom {
public User findByFirstName(String firstName);
#Query("select u.firstName from User u where u.age > 18")
public Set<String> findAllAdultUsers();
public void someCustomMethod(User user);
}
class UserRepositoryImpl implements UserRepositoryCustom {
//I want implement only this method
public void someCustomMethod(User user) {
// Your custom implementation
}
}
If I declare a class, which implements an interface, I have to implement all methods, but I want to write custom logic for only one method.
Is it possible to do this? Maybe I can make this class abstract? Will spring data resolve this?
I think only solution is to split methods in 2 interfaces: first - for spring query method, and second - for custom implementation, as shows in doc: http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.single-repository-behaviour.
But I think solution with abstract class would be more natural and logic: you provide only needed method implementations and spring data do the rest for you.
Let's say you have a repository with a few methods whose implementations are generated by Spring:
interface UserRepository extends CrudRepository<User,String> {
List<User> findUserByLastname(String lastName);
}
In order to add a method with a custom implementation, you need to create another interface that only contains the methods you want to customize, and make your repository extend the custom one:
interface CustomUserRepository {
User someCustomMethod();
}
interface UserRepository extends CrudRepository<User,String>, CustomUserRepository {
List<User> findUserByLastname(String lastName);
}
You can then implement the extra methods by creating an implementation class for the new interface:
class CustomUserRepositoryImpl implements CustomUserRespository {
#Override
User someCustomMethod() {
// implementation goes here.
}
}
The class name is important here: in order for Spring to find it, it should be the name of the interface that is being extended with Impl on the end.
The implementation repository is a normal Spring bean, so you can autowire a constructor to inject various dependencies.
There is a much more detailed tutorial here: https://www.baeldung.com/spring-data-composable-repositories.
Is it possible?
Currently I am using some aspects for my MVC controllers, what works really fine. I'm wrapping their responses and I have desired effect.
I also want to do this with Spring Data JPA repositories. But since they're generated based on the interface e.g:
public interface SomeRepository<T extends Some, ID extends Serializable> extends
BaseRepository<T, ID>, JpaSpecificationExecutor<T> {
public List<T> findById(Long id)
}
It generates me controller which is ready to use:
http://localhost:8080/findById?id=1234
I also want to wrap this controller. Is it possible?
This should work:
#Component
#Aspect
public class MyAdvice {
#Before("execution(* com.company.jpa.SomeRepository+.findById(..))")
public void intercept() { ... }
}
Basically, we are telling the framework to intercept the call to the findById method on any sub-class of SomeRepository.
Here is a sample application demonstrating this in action.
I try to autowire my custom mongo repository (and it seems the constructor is executed) but still the result is null
I've looked at some similar questions
Spring Data Neo4j - #Autowired Repository == null
and
spring data mongo repository is null
but I still don't know how to solve this.
public class TestRepo {
#Autowired
PersonRepository repository;
public void find(String name)
{
System.out.println(repository.findByName(name));
}
}
config
<mongo:repositories base-package="com.yyyy.zzz" />
PersonRepository
public interface PersonRepository extends Repository<Person, BigInteger> {
#Query("{name : ?0}")
public Person findByName(String name);
}
Implementation
public class PersonRepositoryImpl implements PersonRepository{
PersonRepositoryImpl()
{
System.out.println("constructing");
}
public Person findByName(String name) {
...
}
}
if I get the repository bean directly from context it works
Your repository setup looks suspicious. To execute query methods, you don't need to provide an implementation at all. I suspect in your current setup the custom implementation you have in PersonRepositoryImpl "overrides" the query method and thus will be preferred on execution.
If you simply drop your implementation class, Spring Data will automatically execute the query for you on invocation.
Generally speaking, custom implementation classes are only needed for functionality you cannot get through other means (query methods, Querydsl intergration etc.).
I'm trying to make a base class for crud ops but can't quite figure out how to get this part wired up or if it's possible. I'm using an EDMX w/ generated dbcontexts and pocos, so, ideally, I'd like to create a base class from where I can derive all my crud methods.
Interface:
public interface IGenericCrud<T> where T : class
{
void Add(T entity);
}
Implementation:
public abstract class MyImplementation : IGenericCrud<KnownModel>
{
protected myEntities context;
public MyImplementation()
{
context = new myEntities();
}
void Add(KnownModel entity)
{
// This doesn't work, but it's what I'd like to accomplish
// I'd like to know if this possible without using ObjectContexts
context.KnownModel(add entity);
}
}
I believe you should look into the repository pattern. That seems to be what you are looking for.
I want to customize MongoRepository by adding one method, and still using the implemented methods provided by MongoRepository. Below is the code:
public interface TopoRepositoryInterface extends MongoRepository<Topo, String>
{
#Query("{'name':?0}")
public Topo findByName(String name);
public long getPublishedTopoCount();
}
the implementation declaration is:
public class TopoRepositoryImpl extends SimpleMongoRepository<Topo, String> implements TopoRepositoryInterface
If without the customization, method findByName declared in TopoRepositoryInterface can be automatically implemented by adding #Query("{'name':?0}") annotation. But now, since there is interface inheritage, I must add code
#Override
public Topo findByName(String name)
{
Topo topo = getMongoOperations().findOne(Query.query(Criteria.where("name").is(name)), Topo.class);
return topo;
}
Is there any way to write my own code for getPublishedTopoCount() only, and leave findByName() be implemented by #Query annotation? Thank you very much.
You have to split your repository interface into two.
First one - "Custom" containing methods you implement manually would be:
public interface TopRepositoryCustom {
long getPublishedTopoCount();
}
Second one for generated methods:
public interface TopRepository extends MongoRepository<Topo, String>, TopRepositoryCustom {
#Query("{'name':?0}")
Topo findByName(String name);
}
Then you just need to implement first repository and remember to follow proper naming convention. See more at: spring-data mongodb custom implementation PropertyReferenceException and Spring Data MongoDB Custom implementations reference