Xtend picks the wrong overload - spring

I'm playing with Xtend, and have hit a roadblock.
My class uses a Spring Data repository. Here's the interface:
public interface UserRepository extends GraphRepository<UserNode>, RelationshipOperationsRepository<UserNode> {
public UserNode findByEntityId(Long entityId);
}
the super interface of GraphRepository<T> (which is part of Spring Data, not my project) declares the following:
#Transactional
<U extends T> U save(U entity);
#Transactional
<U extends T> Iterable<U> save(Iterable<U> entities);
However, the following code fails for me:
// UpdateUserProcessorExample.xtend
class UpdateUserProcessorExample {
#Autowired
UserRepository repository
def updateUser()
{
var user = repository.findByEntityId(1L)
// The following line generates an error:
repository.save(user)
}
}
This generates:
Bounds mismatch: The type argument is not a valid substitute for
the bounded type parameter of the method
save(Iterable)
It appears as though Xtend is picking the wrong overloaded method.
I've tried adding type hints, ala:
var UserNode user = repository.findByEntityId(1L)
But this still generates the same error.
What am I doing wrong here?

On the Xtend mailing list, Sven advised he's raised a bug for this issue:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=413138
He also offered the following work-around:
A not so nice solution is to override the respective methods in
UserRepository and replace T by UserNode, like this :
public interface UserRepo extends GraphRepository<UserNode> {
UserNode findByEntityId(Long entityId);
#Override UserNode save(UserNode entity);
#Override <U extends UserNode> Iterable<? extends U> save(Iterable<? extends U> entities);

I don't understand why you have introduced additional type parameters on the methods, can't you you just use the one from the class level?
#Transactional
T save(T entity);
#Transactional
Iterable<? extends T> save(Iterable<? extends T> entities);
That should work.

Related

How can I create a Pointcut or Around for extended classes with shared interface?

I have an abstract service class.
abstract class AbstractService<T> {
public void saveNew(T entity) {
}
}
And I have two more abstract classes extends AbstractService and implement a shared interface.
abstract class MoreAbstractService2<T extends Some2>
extends AbstractService<T>
implements SharedInterface {
}
abstract class MoreAbstractService3<T extends Some3>
extends AbstractService<T>
implements SharedInterface {
}
Now I want to validate the entity argument on these two extending services' saveNew(T) method.
How can I define a #Pointcut and (or) an #Around for following conditions?
extends the AbstractService class
implements the SharedInterface interface
you can use within as following:
within(com.somepackage.Super+)
where com.somepackage.Super is the fully qualified base class name and + means "all subclasses". Other pointcut is
execution(* com.somepackage.Super+.*(..))
R.G's solution has a few disadvantages:
The pointcut matches too many joinpoints.
Thus it needs reflection in order to filter out the unnecessary ones.
I am going to show you a stand-alone AspectJ solution (no Spring, I am not a Spring user), but the aspect would look just the same in Spring, you only need to make it a #Component or declare a #Bean factory in your configuration. But the same applies to all the classes you want to intercept, of course.
Because I prefer a full MCVE with all necessary dependency classes in order for you to be able to copy, compile and run it, and because I also added negative test cases (sub-classes only extending the abstract base class or only implementing the interface), this is a lot of code. So please bear with me:
Abstract classes, interface and helper classes:
package de.scrum_master.app;
public abstract class AbstractService<T> {
public void saveNew(T entity) {
System.out.println("Saving new entity " + entity);
}
}
package de.scrum_master.app;
public class Some2 {}
package de.scrum_master.app;
public class Some3 {}
package de.scrum_master.app;
public abstract class MoreAbstractService2<T extends Some2>
extends AbstractService<T>
implements SharedInterface {}
package de.scrum_master.app;
public abstract class MoreAbstractService3<T extends Some3>
extends AbstractService<T>
implements SharedInterface {}
package de.scrum_master.app;
public interface SharedInterface {
void doSomething();
}
Driver application (AspectJ + POJOs, not Spring):
This driver class contains some static inner classes subclassing the given base classes and/or implementing the shared interface. Two are used for positive tests (should be intercepted), two for negative tests (should not be intercepted). Each class also contains an additional method as another negative test case which should not be matched - better safe than sorry.
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
// Should be intercepted
InterceptMe1 interceptMe1 = new InterceptMe1();
interceptMe1.saveNew(new Some2());
interceptMe1.doSomething();
interceptMe1.additional();
printSeparator();
// Should be intercepted
InterceptMe2 interceptMe2 = new InterceptMe2();
interceptMe2.saveNew(new Some3());
interceptMe2.doSomething();
interceptMe2.additional();
printSeparator();
// Should NOT be intercepted
DontInterceptMe1 dontInterceptMe1 = new DontInterceptMe1();
dontInterceptMe1.saveNew(new Some2());
dontInterceptMe1.additional();
printSeparator();
// Should NOT be intercepted
DontInterceptMe2 dontInterceptMe2 = new DontInterceptMe2();
dontInterceptMe2.additional();
printSeparator();
}
private static void printSeparator() {
System.out.println("\n----------------------------------------\n");
}
static class InterceptMe1 extends MoreAbstractService2<Some2> {
#Override
public void doSomething() {
System.out.println("Doing something in MoreAbstractService2<Some2>");
}
public void additional() {
System.out.println("Additional method in MoreAbstractService2<Some2>");
}
}
static class InterceptMe2 extends MoreAbstractService3<Some3> {
#Override
public void doSomething() {
System.out.println("Doing something in MoreAbstractService3<Some3>");
}
public void additional() {
System.out.println("Additional method in MoreAbstractService3<Some3>");
}
}
static class DontInterceptMe1 extends AbstractService<Some2> {
public void additional() {
System.out.println("Additional method in AbstractService<Some2>");
}
}
static class DontInterceptMe2 implements SharedInterface {
#Override
public void doSomething() {
System.out.println("Doing something in SharedInterface"); }
public void additional() {
System.out.println("Additional method in SharedInterface");
}
}
}
Aspect:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
#Aspect
public class EntityValidationAspect {
#Before(
"execution(* saveNew(*)) && " +
"args(entity) && " +
"target(de.scrum_master.app.SharedInterface) && " +
"target(de.scrum_master.app.AbstractService)"
)
public void validateEntity(JoinPoint thisJoinPoint, Object entity) {
System.out.println("-> Pre-save entity validation: " + entity);
}
}
As you can see, the aspect uses two target() pointcuts which must both match. It also specifically targets any saveNew method with a single argument saveNew(*), binding that argument as an advice method parameter via args().
For demonstration's sake I do not validate anything (I don't know how you want to do that) but just print the entity. Thus, a #Before advice is sufficient. If in case of negative validation you want to throw an exception, this advice type is also okay. If you need to do more, such as manipulate the entity's state or replace it before passing it on to the target method, call an alternative target method instead or none at all, return a specific result (in case of non-void methods, here not applicable), handle exceptions from the target method etc., you ought to use an #Around advice instead.
Console log:
-> Pre-save entity validation: de.scrum_master.app.Some2#28a418fc
Saving new entity de.scrum_master.app.Some2#28a418fc
Doing something in MoreAbstractService2<Some2>
Additional method in MoreAbstractService2<Some2>
----------------------------------------
-> Pre-save entity validation: de.scrum_master.app.Some3#5305068a
Saving new entity de.scrum_master.app.Some3#5305068a
Doing something in MoreAbstractService3<Some3>
Additional method in MoreAbstractService3<Some3>
----------------------------------------
Saving new entity de.scrum_master.app.Some2#1f32e575
Additional method in AbstractService<Some2>
----------------------------------------
Additional method in SharedInterface
----------------------------------------
Et voilĂ  - the aspect does exactly what you asked for, as far as I understand your requirement. :-) More specifically, it does not get triggered in the third case when saveNew is being called, but the class does not implement the interface.
Following code can be used for the validation mentioned.
The point cut is to intercept on the execution of a specific method for the subclasses of AbstractService and the code logic is to only validate if SharedInterface is a superinterface of the target bean.
The use of isAssignableFrom() is required as the interfaces proxied by the AOP proxy does not include SharedInterface. As per my understanding , a pointcut expression to match the second criteria will not be possible for the same reason and hence handled the requirement in the code logic.
Hope this helps
#Aspect
#Component
public class ValidationAspect {
#Pointcut("execution(* package.to.AbstractService+.saveNew(..))")
public void isAbstractServiceType() {
}
#Around("isAbstractServiceType() && args(entity) && target(bean)")
public void validateEntityArugments(ProceedingJoinPoint pjp, Object entity, Object bean) throws Throwable {
if (SharedInterface.class.isAssignableFrom(bean.getClass())) {
System.out.println(entity);
// ..validate
}
pjp.proceed();
}
}

Deprecated QuerydslJpaReposiotry does not work anymore

I have a custom repository that needs the functionality of Querydsl as well as PagingAndSortingRepository. Till now my custom repository was like
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QuerydslPredicateExecutor<T> {
// Overriden methods
}
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
// Overriden implementations of methods defined in the interface
}
The great thing about this was that my custom implementation was not very different from the default implementation provided by QuerydslJpaRepository and thus I would use the super class methods with some modifications in mine like
public class CustomPagingSortingQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaRepository<T, ID> implements CustomPagingSortingQuerydslRepository<T, ID> {
#Override
#NonNull
public Optional<T> findOne(#NonNull Predicate predicate) {
return super.findOne(modifierMethod(predicate));
}
#Override
#NonNull
public <U extends T> U save(#NonNull U entity) {
return super.save(otherModifierMethod(entity, false));
}
#Override
#NonNull
public <S extends T> S saveCustom(#NonNull S entity) {
return super.save(otherModifierMethod(entity, false));
}
}
Note that I also have a saveCustom defined by me in the custom interface and I am providing its implementation with the help of the parent class.
This worked great but after Spring Boot 2.1, QuerydslJpaRepository has been deprecated in favour of QuerydslJpaPredicateExecutor. Now this class does not provide implementations of save or delete and thus I cannot use the SimpleJpaRepository methods if my implementation class inherits from QuerydslJpaPredicateExecutor.
In short, I need to reimpelement query and save/delete methods in my custom repository along with some custom methods of mine and I don't want to implement them from scratch. The current deprecation means my implementation can extend either from QuerydslJpaPredicateExecutor which provides implementation of query methods only or from SimpleJpaRepository which means I lose the functionality of querydsl in my implementation.
What I've done till now
To work around this I have created 2 repositories
#NoRepositoryBean
public interface CustomPagingSortingRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
// Only overrides save and delete type of methods and includes my customSave method
#NoRepositoryBean
public interface CustomQuerydslRepository<T, ID> extends QuerydslPredicateExecutor<T> {
// Overrides all methods of the superclass and includes any custom methods of mine
}
and I have implemented them separately like
#NoRepositoryBean
public class CustomPagingSortingRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomPagingSortingRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
#NoRepositoryBean
public class CustomQuerydslRepositoryImpl<T, ID extends Serializable> extends QuerydslJpaPredicateExecutor<T> implements CustomQuerydslRepository<T, ID> {
// Implements all the methods of the interface using the parent class methods
}
and I inherit these 2 interfaces into my custom interface
#NoRepositoryBean
public interface CustomPagingSortingQuerydslRepository<T, ID> extends CustomPagingSortingRepository<T,ID>,CustomQuerydslRepository<T, ID> {
}
I thought this would work but this throws a type error which on close inspection I found to be because Spring is trying to create an implementation of customSave by itself and since it doesn't understand what this method has to do, it throws an error.
I am really in a fix now since the deprecated way was extremely clean and I don't want to implement half a dozen Beans for this to work.
P.S.
I have been thinking using Composition instead of Inheritance to get a handle to SimpleJpaRepository and QuerydslJpaPredicateExecutor and use the methods in them that way but I have a feeling this is going to be against injection and a bad practice.

Custom delete method in JpaRepository

I'd like to know if there's a way of overriding the delete method for some of my JpaRepository's without having to override the rest of the methods.
Currently I have something like
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
And I'd like to override the delete(T Entity) method in CrudRepository. To do so I've tried implementing the UserRepo but then I have to implement all the findByX and haven't really find anything around on how to properly do that.
Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)?
Thanks in advance!
Not sure I understand you clear enough, but lets try:
... I have to implement all the findByX ...
You don't, spring will generate JPQL snippet if you name methods in your interface with suitable convection please take a look at this and this articles
... Is there any annotation to add to a function in the Entity class
so it runs when you call UserRepo.delete(myUser)? ...
You can use #PreRemove / #PostRemove annotation on method in your entity class:
#PreRemove / #PostRemove
public void someMethod() { ... }
In addition to Raheela Aslam post:
Spring-data documentation has an example of how you can override standard repository methods, for example:
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}
You can read about it there:
https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations
UPD:
Read it carefully, because there are some important things, e.g
The most important part of the class name that corresponds to the fragment interface is the Impl postfix.
Also the documentation says:
Custom implementations have a higher priority than the base implementation and repository aspects.
If you want to keep Spring's behavior for deletion, but want to have some logic to be executed either before or after, you may utilize java8's interface default methods, and try the following :
public interface UserRepo extends JpaRepository<User, Long> {
default void customDelete(User user) {
// before logic
// ..
delete(user); // actual call to deletion
// after logic
// ..
}
}
There are several ways to do this depending on what you're trying to do:
Use method naming, and let Spring derive the JPQL query from the naming (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-from-method-names/)
Use the Query annotation and add the desired JPQL query in the annotation (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-the-query-annotation/)
Use a named query (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-named-queries/)
I prefer to use method naming if possible, the method name gets long, but you know exactly what it does by looking at it.
In your case code will be like as below:
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
public interface UserRepositoryCustom {
void deleteByEmail(String email);
}
public interface UserRepositoryImpl implements UserRepositoryCustom {
public void deleteByEmail(String email) {
//provide your custom implimentation
}
}
Hi you can write your own Interface write implementation with EntityManager and
extend in you interface here is the sample :
https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
Actually one more way is writing by soemthing like :
User findByUsername(String username) // it will find the user by specific username
spring data will create you an implementation of this method
The same way you can create your own delete method
Here is useful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
In this link you can go to part 2.3 QueryMethods:
https://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/html/jpa.repositories.html
You can also define #NameQuery in your entity class:
#Entity
#Table(name = "employee", schema="spring_data_jpa_example")
#NamedQuery(name = "Employee.yourMethodQueryName",
query = "yourQuery"
)
public class Employee {}
#Repository
public interface EmployeeRepository extends JpaRepository<Employee,Long> {
List<Employee> yourMethodQueryName(Your list of params);
}
Here is link with sample:
https://www.logicbig.com/tutorials/spring-framework/spring-data/jpa-named-queries.html
I think this is helpful for you
public interface UserRepo extends JpaRepository<User, Long> {
#Modifying
#Query("delete from User u where u.email = ?1")
void deleteByEmail(String email);
}

The method findOne(Example<S>) in the type QueryByExampleExecutor<Contact> is not applicable for the arguments (Long)

The find methods not working for me but in other project work fine .
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entities.Contact;
public interface ContactRepository extends JpaRepository<Contact, Long>{
}
in my controller i call find one but give works.
#RequestMapping(value="/contact/{id}",method=RequestMethod.GET)
public Contact getContact(#PathVariable Long id){
return repo.findOne(id); //here give a error
}
Some CRUD Repository methods got renamed in Spring Data and
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
is one of them. Now you should use the
public interface CrudRepository<T, ID> extends Repository<T, ID> {
Optional<T> findById(ID id);
For more info which methods got renamed see this blog improved-naming-for-crud-repository-methods
There is still a findOne method around but this is from
public interface QueryByExampleExecutor<T> {
<S extends T> Optional<S> findOne(Example<S> example);
which is also an interface of the SimpleJpaRepository. So that is why you got your error, since this method awaits an Example as parameter.

Spring Data Rest Save Iterable Entity

I've tried many different ways to pass an array of JSON to a Spring Data Rest Repository, not sure how to do it. I have a custom respository interface that is extending Repository:
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends Repository<T, Long> {
T save(T entity)
List<T> save(Iterable<T> entities)
}
I can save a single entity, but when I try to pass an array of JSON objects I get an error cannot deserialize instance...
Not sure how to pass the object so that I can do a batch insert.
Unfortunatly you don't post the code that uses your interface, bug if you are actually passing an array as you describe in the question, you are not calling List<T> save(Iterable<T> entities) but T save(T entity). Arrays are not Iterables so the compiler will interpret your array as T and since an array is not an entity you get the error.
Convert the array to an Iterable to fix this. Arrays.asList(someArray) does the trick.
I seemed to work around it by overriding the save method, I'm sure there is a better way, I am open to suggestions.
BaseRepository
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends Repository<T, Long> {
#RestResource(path="byIdIn",rel="byIdIn")
#Query("select r from #{#entityName} r where r.id in :q")
Page<T> findByIdIn(#Param("q") List<Long> q, Pageable pageable)
Page<T> findAll(Pageable pageable)
T findOne(ID id)
T save(T entity)
T delete(ID id)
}
ContactRepository
#RepositoryRestResource(collectionResourceRel="contacts", path="contacts")
interface ContactRepository extends BaseRepository<Contact, Long>, ContactRepositoryCustom {
}
ContactRepositoryCustom
interface ContactRepositoryCustom {
public <S extends Contact> S save(S entity)
}
ContactRepositoryImpl
#NoRepositoryBean
class ContactRepositoryImpl implements ContactRepositoryCustom {
#PersistenceContext
private EntityManager em
#Transactional
#Override
public <S extends Contact> S save(S entity) {
Contact contact = entity as Contact
try {
em.persist(contact)
contact.getComment().each {
Comment comment = new Comment(contact, it)
em.persist(comment)
}
} catch (Exception e) {
println e
}
return contact
}
}
This is just a sample, it needs some cleaning up, but I have the save() method working as expected. I just don't want to over do it if there is a baked in way in Spring Data / Spring Data Rest to do this kind of thing with annotations without having to roll a solution like this. I searched through the docs and online, but did not find a solution. I may have overlooked something, not sure.

Resources