SpringData extending JpaSpecificationExecutor error - java

I have very strange problem. In my repository, i need to extend JpaSpecificationExecutor<T> interface to be able to use findAll(Specification<T>, Pageable) for custom query paging.
But, when I use the JpaSpecificationExecutor,
public interface DescriptionRepository extends ParentRepositoryCustom<Description, Long>,
JpaSpecificationExecutor<Description> {
}
application won´t build, throwing No property count found for type class Description exception.
My Description class has no count attribute. When I remove JpaSpecificationExecutor from repository, everything works well again.

I came across the same exception. In my case, the reason was that the
ParentRepositoryImpl was NOT exending correctly SimpleJpaRepository
which is an implementation of JpaSpecificationExecutor.
So when Spring try to resolve the query names, it exludes the method names belonging to what Spring call the repositoryBaseClass of your implementation. It s in the class org.springframework.data.repository.core.support.DefaultRepositoryInformation
public boolean isBaseClassMethod(Method method) {
return isTargetClassMethod(method, repositoryBaseClass);
}
Check that repositoryBaseClass is what you expect. It should defines the "count" method.
If you don't extends the correct superclass, the method ("count" in your case) is not excluded form resolution and Spring tries to build a query by creating it according to its name structure ... and in that case fragment of name are tested against your entity property.

Related

Dynamic filtering of database entries based on requester ip address

I have a requirement for my spring-boot server project to dynamically filter the returned database rows based on the requester ip address. The filtering happends based on a flag column, which can either be true or false. The allowed ip addresses are set in the application configuration. So if the requesting ip is in the allowed ip addresses, I return all rows, otherwise only the rows, that have the flag set to true.
As the filtering has to happen both in a view library that uses the generic repository implementation and in the automatically generated rest data api, I would like to implement the filtering logic at the repository level to reduce code duplication. I have around 10 different repositories, that need this logic.
My current approach has been to use the composite repository approach, where I have a CustomRepositoryImpl, which overrides all crud repository methods and applies the filtering. All repository interfaces reference this implementation. Hovewer, the issue with this approach is that the CustomRepositoryImpl cannot know the generic type of each repository, to make the corresponding db query.
For example:
public interface FilterRepository<T> {
List<T> findAll();
}
// Overrides all methods with filtering logic
public class FilterRepositoryImpl<T> {
...
public List<T> findAll()
{
Class<T> klass = ??? // How to determine object class variable to implent query
query = entityManager.createQuery("select e from " + klass.getSimpleName() + " e where {filterLogic}");
}
}
public interface Entity1Repository extends CrudRepository<Entity1, long>, FilterRepository<Entity1>
{
}
public interface Entity2Repository extends CrudRepository<Entity2, long>, FilterRepository<Entity2>
{
}
The common approach of passing the Class<T> type to the method, i.e.
public List<T> findAll(Class<T> klass)
would not work, as I have to stick to the default method signatures for reusability by all followup libraries.
I have seen, that in the case of BaseRepository implementations its possible to inject the domainObject of Class through spring, but the same approach doesn't seem to work with the Impl approach. Is there any way around this? From what I have understood, if I use the BaseRepository approach, it overrides all repositories in my implementation. This would not be a solution here, as I want to add the filtering selectively only to some repositories. Do you have any other suggestions?
Thanks a lot and best regards

How to detach entity from persistence context, if using Spring Data Repositories (Spring 4)

I need to detach an entity from persistence context, within a spring-boot application.
I have the following base repository:
interface EntityRepository extends CrudRepository<Entity, Long>
Obviously this is not offering any detach(..)-operation.
I found an answer, which is actually not working for me:
SO Post.
I tried the same, but it seems that my entity is not detached(as if im changing any field, it gets still persisted)
Custom Repo:
interface MyCustomEntityRepository {
void detach(Entity ent)
}
Interface Impl:
class MyCustomEntityRepositoryImpl implements MyCustomEntityRepository{
#PersistenceContext
private EntityManager em;
public void detach(Entity ent) {
em.detach(ent);
}
}
But I cant extend EntityRepository with MyCustomEntityReposity, as this results in:
No property detach found for type Entity!
I managed to get it compiled without errors, by not extending EntityRepository. Also changin CrudRepository to JpaRepository
But still my entity is not getting detached, but in linked post, the QA says, that it is working for him/her.
The actual reason for detaching the object, is to be able to perform some validations within an #EntityListener, by checking the currently stored entity in db, with the currently changed entity instance, which should be detached.
Does anyone see some errors or give me a clue, what Im doing wrong ?
Using: Spring-boot(1.4.0-release), Spring 4, JPA
Does anyone see some errors or give me a clue, what Im doing wrong?
Although it is hard to tell, what might be part of your actual problem and what is just sloppy question editing.
Your interface does not compile
interface MyCustomEntityRepository {
detach(Entity ent)
}
should probably be
interface MyCustomEntityRepository {
void detach(Entity ent)
}
Your implementation of your custom interface should implement the interface:
class MyCustomEntityRepositoryImpl {
should probably be
class MyCustomEntityRepositoryImpl implements MyCustomEntityRepository {
If problems persist, please show the actual code you are using with the actual exception, including the stacktrace.

Resolving subdocument types with Spring Data and MongoDB

I'm encountering an error with a Spring Data repository as it attempts to resolve a property expression:
public interface ContractRepository
extends MongoRepository<Contract,String> {
public List<Contract> findByCodeBindings(String binding);
}
Here's the relevant parts of Contract:
#Document(collection="CONTRACTS")
public class PersistentContract extends BaseContract {
#PersistenceConstructor
public PersistentContract(String name, Version version, Code code) {
super(name, version, code);
}
}
Code is an interface implemented by CodeImpl. It contains a property bindings, which has a getter and setter in Code. So the query's property expression is designed to find those contracts with a nested Code document containing a given binding. So far, so good.
However, the problem is an IllegalArgumentException is getting thrown:
java.lang.IllegalArgumentException: No property bindings found on my.company.Code!
org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:225)
Debugging that section of code shows that Spring Data is picking apart the expression and determines there's a property of type Code. However, because Code is an interface, it has no properties listed.
Is there a means to hint to Spring Data that either Code has this property or that CodeImpl is the actual type of the code property? I'm surprised that the library doesn't attempt to parse the getters or setters of the interface.
This is using spring-data-commons 1.5.1.RELEASE and spring-data-mongodb 1.2.1.RELEASE.
Appreciate the help.
My solution was to avoid interfaces at all in the persistent object. So BaseContract became the following:
public abstract class BaseContract<T extends Code> {
public abstract T getCode();
}
And PersistentContract was implemented in terms of concrete classes:
public class PersistentContract extends BaseContract<CodeImpl> {
}
This seems to strike the right balance between coding against interfaces in the base class and satisfying Spring Data's need for concrete classes.

Understanding the Spring Data JPA #NoRepositoryBean interface

I encountered the #NoRepositoryBean interface several times whilst reading the Spring Data documentation.
To quote from the documentation:
If you're using automatic repository interface detection using the
Spring namespace using the interface just as is will cause Spring
trying to create an instance of MyRepository. This is of course not
desired as it just acts as indermediate between Repository and the
actual repository interfaces you want to define for each entity. To
exclude an interface extending Repository from being instantiated as
repository instance annotate it with #NoRepositoryBean.
However, I am still not sure when and where to use it. Can someone please advise and give me a concrete usage example?
The annotation is used to avoid creating repository proxies for interfaces that actually match the criteria of a repo interface but are not intended to be one. It's only required once you start going into extending all repositories with functionality. Let me give you an example:
Assume you'd like to add a method foo() to all of your repositories. You would start by adding a repo interface like this
public interface com.foobar.MyBaseInterface<…,…> extends CrudRepository<…,…> {
void foo();
}
You would also add the according implementation class, factory and so on. You concrete repository interfaces would now extend that intermediate interface:
public interface com.foobar.CustomerRepository extends MyBaseInterface<Customer, Long> {
}
Now assume you bootstrap - let's say Spring Data JPA - as follows:
<jpa:repositories base-package="com.foobar" />
You use com.foobar because you have CustomerRepository in the same package. The Spring Data infrastructure now has no way to tell that the MyBaseRepository is not a concrete repository interface but rather acts as intermediate repo to expose the additional method. So it would try to create a repository proxy instance for it and fail. You can now use #NoRepositoryBean to annotate this intermediate interface to essentially tell Spring Data: don't create a repository proxy bean for this interface.
That scenario is also the reason why CrudRepository and PagingAndSortingRepository carry this annotation as well. If the package scanning picked those up by accident (because you've accidentally configured it this way) the bootstrap would fail.
Long story short: use the annotation to prevent repository interfaces from being picked up as candidates to end up as repository bean instances eventually.
We can declare a new interface as our custom method:
#NoRepositoryBean
public interface ExtendedRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
List<T> findByAttributeContainsText(String attributeName, String text);
}
Our interface extends the JpaRepository interface so that we'll benefit from all the standard behavior.
You'll also notice we added the #NoRepositoryBean annotation. This is necessary because otherwise, the default Spring behavior is to create an implementation for all subinterfaces of Repository.
public interface ExtendedStudentRepository extends ExtendedRepository<Student, Long> {
}

Spring Data MongoDB tries to generate queries for custom repository methods

Based on the Spring Data Document documentation, I have provided a custom implementation of a repository method. The custom method's name refers to a property which doesn't exist in the domain object:
#Document
public class User {
String username;
}
public interface UserRepositoryCustom {
public User findByNonExistentProperty(String arg);
}
public class UserRepositoryCustomImpl implements UserRepositoryCustom {
#Override
public User findByNonExistentProperty(String arg) {
return /*perform query*/;
}
}
public interface UserRepository
extends CrudRepository<?, ?>, UserRepositoryCustom {
public User findByUsername(String username);
}
However, perhaps because of the method name I've chosen (findByNonExistentPropertyName), Spring Data attempts to parse the method name, and create a query from it. When it can't find the nonExistentProperty in User, an exception is thrown.
Possible resolutions:
Have I made a mistake in how I provide the implementation of the custom method?
Is there a way to instruct Spring to not attempt to generate a query based on this method's name?
Do I just have to avoid using any of the prefixes that Spring Data recognizes?
None of the above.
Thank you!
Your implementation class has to be named UserRepositoryImpl (if you stick to the default configuration) as we try to look it up based on the Spring Data repository interface's name being found. The reason we start with that one is that we cannot reliably know which of the interfaces you extend is the one with the custom implementation. Given a scenario like this
public interface UserRepository extends CrudRepository<User, BigInteger>,
QueryDslPredicateExecutor<User>, UserRepositoryCustom { … }
we would have to somehow hard code the interfaces not to check for custom implementation classes to prevent accidental pick-ups.
So what we generally suggest is coming up with a naming convention of let's say the Custom suffix for the interface containing the methods to be implemented manually. You can then set up the repository infrastructure to pick up implementation classes using CustomImpl as suffix by using the repository-impl-postfix attribute of the repositories element:
<mongo:repositories base-package="com.acme"
repository-impl-postfix="CustomImpl" />
There's more information on that in the reference documentation but it seems you have at least briefly checked that. :)

Categories

Resources