I am implementing an interface in my project(A spring MVC project) which has ten methods. I have implemented two methods and want spring to continue using the interface to query the database unless all of the methods are implemented.
The interface is having #Query annotation and is working fine, but the idea is to implement the method using criteria builder.
My interface
#Repository
public interface TagDAO extends JpaRepository<Tag, Integer> {
#Query("SELECT count(*) from Tag t WHERE t.isActive = true")
public Long getTagCount() throws DataAccessException;
#Query("SELECT t from Tag t WHERE t.tagName = :tagName")
public Tag findByTagName(#Param("tagName") String tagName) throws
DataAccessException;
...........
rest of the methods
}
I have implemented three methods in a class TagDAOImpl but want that the implementation is not to be used in my project unless the implementation is complete. Is there any way to force the use of interface until I complete the implementation?
Related
// Interface 1:
#Repository
public interface EmpSpannerrepo extends SpannerRepository<Emp,Integer>{
}
// Interface 2:
#Repository
public interface EmpPsqlrepo extends JpaRepository<Emp,Integer>{
}
// Transfering emp details to Psql server and Spanner
public void insertEmpSpannerDetails(List<Emp> emps,int batchSize) throws SQLException, InterruptedException{
common.insert(emps,batchSize,Object);
}
public void insertEmpPsqlDetails(List<Emp> emps,int batchSize) throws SQLException, InterruptedException{
common.insert(emps,batchSize,Object);
}
Need this object to determine at runtime where to push the code either to spanner or PSql
Insert function is exactly same in both cases so rather than writing the same code again , how can i do that with a common code?
// What have i tried?
Tried extending both interfaces to a common one and then using that to save the list , but again it gives me error saying SpannerRepoFactory does not support Query by Example.
Any hints are appreciated.
Any interface that extends Spring Cloud GCP's SpannerRepository will have a concrete instance created for you at runtime. Spring Data JPA will do the same for its interfaces. Since Spring Cloud GCP's Spring Data Spanner implementation is not a JPA implementation, it's not valid for a repository interface to extend both, SpannerRepository and a JPA repository.
In this case, you'll have to write a common layer to invoke correct methods in each repository. By the way, SpannerRepository does not have an insert() method; it has save().
My JPA repositories extend a custom interface that carries annotations for handling authorization in a generic way.
public interface MultiTenantCrudRepo<T, ID> extends CrudRepository<T, ID>
This interface adds #PreAuthorize, #PostAuthorize, #PreFilter and #PostFilter annotations to the methods of CrudRepository.
Further, for some entities, I have the need to implement soft deletion. For this purpose, I created a "SoftDeleteRepository" like this:
public interface SoftDeleteRepository<T extends BaseEntity<I> & SoftDeletable, I extends Serializable> extends CrudRepository<T, I> {
#Query("update #{#entityName} e set e.isDeleted = true where e.id = ?#{#entity.id}")
#Modifying
#Override
public void delete(#Param("entity") T entity);
You can see it adds #Query annotations to implement the functionality I need.
Both interfaces work independently as expected, but when a repository required both attributes (authorization and soft deletion) like this
public interface FooRepo extends SoftDeleteRepository<Foo, Long>, MultiTenantCrudRepo<Foo, Long> {
it seems like only the annotations of the first interface after "extends" are effective. So in this case, I get a FooRepo that supports soft delection but without authorization validation.
What is the best way to get both to work?
Guess that it is a tricky thing to do because it actually would be multi inheritance thing which Java does not support, for example see this.
What would be chosen if there were two of the same annotations with different parameters, for example?
Many frameworks - like Spring data - do just fine when checking for inheritance of annotations but guess only if there is no multi-inheritance and/or with same annotations. These frameworks might use reflection to go up on the "implements tree" but might choose only one path because of the above or if well implemented throw an exception.
Because of this I am afraid you need to do something like:
public interface SoftDeleteMultitenantRepository
extends MultiTenantCrudRepo<Foo, Long> {
// a copy of your soft delete method here
}
So I was following the tutorial here: https://spring.io/guides/gs/accessing-data-jpa/
and it works fine, I'm trying to implement it in my application (Because it makes JPA so easy to use), but I'm confused.
Where it has
#Bean
public CommandLineRunner demo(CustomerRepository repository)
and then it acts on the repository
repository.save(new Customer("Jack", "Bauer"));
repository.save(new Customer("Chloe", "O'Brian"));
How can it act on an interface? CustomerRepository is an interface, and I can't instantiate it
CustomerRepository c = new CustomerRepository()
cant be done, and I don't have any classes that implement the interface. I just wanted to do something like
CustomerRepository c = new CustomerRepository()
c.save(new Customer("whatever", "whatever")
but I can only use it in the CommandLineRunner bean method. Why can I do this with commandlinerunner but cant do it with another class?
I was thinking I could just make a class that extends CustomerRepository, but then I read that the interface actually does all the method implementation itself (JPA does it) so you don't have to worry about it.
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
so if I extended it, wouldn't I have to override the findbylastname() method, meaning JPA wouldn't do it itself?
Thanks for any assistance.
so if I extended it, wouldn't I have to override the findbylastname()
method, meaning JPA wouldn't do it itself?
No, it is not JPA which does the job but Spring which generates by APO some JPA processings.
With Spring Repository, you have multiples ways of doing :
write your own SQL/JPQL query.
use naming convention in the method name to write the query
In both cases, you don't need to implement directly the interface you declare here :
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
Because as you understood, the job is performed for you by Spring.
For example, in the case you quote, you use naming convention in the method name to write the query.
When Spring inspects your interface and sees the method findByLastName(String lastName), it associates the method name to a query which does a find with a match by lastName field. So, it generate a JPQL query like that :
select c from Customer c where c.lastName=%lastName
and it sets the lastName param with the effective parameter used when the method is call.
I extended it, wouldn't I have to override the findbylastname()
method, meaning JPA wouldn't do it itself ?
No, you don't need to implement the methods as spring-data-jpa will take care of it, you can look here on how Spring data repository interfaces are actually implemented by proxy at runtime.
The main point that you need to remember is that spring data has got few rules to derive the sql queries from the method names (like findByLastName(), findByLastnameOrderByFirstnameAsc(), etc..), you can look here to understand how method names work and they are related to field names of your entity bean.
If you wanted to write some complex queries which can't be derived from method names you can use #Query for your methods.
If I made a class public class Cust implements CustomerRepository what
would I do when it asks me I have to implement the
findByLastName(String lastName); method that JPA is supposed to take
care of ?
If you wanted to implement repository to provide your custom behaviour for few of the methods for few of your methods, you can do that (like class Cust implements CustomerRepository), you can refer the section "Using JpaContext in custom implementations", it is well explained in the ref doc.
I want to use RepositoryItemWriter to write batch entities using the default implementation of SimpleJpaRepository.
#Autowired
private MyCrudRepository crudDao;
RepositoryItemWriter<HrsGiataId> w = new RepositoryItemWriter<>();
w.setRepository(crudDao);
w.setMethodName("deleteInBatch");
public interface MyCrudRepository extends CrudRepository<MyEntity, Long> {}
But the code above will not work as the w.setMethodName requires a method name from the CrudRepository interface, even though the default implementation for the crudrepository is SimpleJpaRepository, which has the deleteInBatch() method.
So, what can I do to make use of the spring crud repository specific jpa method?
I don't believe that the writer requires a method from the CrudRepository. You should be able to specify any method name you want. If not, I'd raise that as a bug in Jira (https://jira.spring.io/browse/BATCH/).
I am confused. I could not find out, how to define together custom "search" methods with methods that were loaded with help of spring-data-rest.
Could you answer me, does the framework has this possibility "out-of-box"?
And if has, could you tell me, where can i find it?
For a deeper understanding my situation i describe my issue:
class UserService {
public String getListOfWaitingUsers() {
return userRepository.findAll(UserSpecification.isWaiting());
}
}
public interface UserRepository extends PagingAndSortingRepository<User, Long>{
Page<User> findByNameLike(#Param("name") String name, Pageable pageable);
}
I want that it to be like:
/user/search/
findByNameLike
findWaitingUsers
How to implement that my methods of specifications or services (there is not method in repository) will define with path "/resource_name/search/METHOD_NAME" ( methods of repository + ( METHODS SERVICES OR SPECIFICATIONS)
Spring Data REST framework is based on Spring Data Respository, so your service class can be ignored here.
All methods that are not part of CRUD/Paging Repository as exposed as "search" methods provided you annotated all parameters with #Param annotation. So in your case, you need to implement your method following the conventions outline in Spring Data commons docs. So once you have implementation for findByNameLike method, the method would be exposed as ../search/findByNameLike URL. If needed, you could customize the rel and path with #RestResource annotation.
Also note your UserRepository should ideally be working only on User object and hence the methods you defined. In your case, UserRepository is returning Process/ProcessContext objects? Instead it should be like below
public interface UserRepository extends PagingAndSortingRepository<User, Long>{
Page<User> findByNameLike(#Param("name") String name, Pageable pageable);
}