Comments (14)
Oliver Drotbohm commented
Quite a bit of the stuff you're asking for has been introduced in recent changes. Repository
does not contain any methods anymore. We even provide a @RepositoryDefinition
annotation that can be used instead of extending the interface. CRUD methods can be selectively added simply by declaring the methods in the repository interface extending Repository
(or being annotated) and following the names of the mthods in CrudRepository
.
However we still require the repository to be bound to a domain class for a variety of reasons. First a repository is per domain class by definition (see Eric Evans' Domain Driven Design book). Beyond that we think that placing persistence methods for a variety of entities into a single interface as this violates separation of concerns, creates a "god" repository everyone will probably refer to and generally feels not right.
So I think chances are not that high to introduce a general mechanism like this but I'd be interested to see an example how you imagine stuff to look like and the concerns I just mentioned not being violated
from spring-data-commons.
Pavan Veeramachineni commented
Something like a neutral repository would be very helpful when executing named native queries against entities that do not have an underlying table. This seems like a hack to use the repository infrastructure but definitely eliminates the need to write the same boiler plate code using entity manager over & over again. A simple example of such an entity with the named native query would be:
@Entity
@SqlResultSetMapping(name = "AnEntity.implicit", entities = @EntityResult(entityClass = AnEntity.class))
@NamedNativeQuery(name = "AnEntity.find",
query = "SELECT A.CODE CODE, A.DESCR AS DESCRIPTION FROM A_MV A, B_MV B" +
" WHERE A.CODE= B.CODE ORDER BY A.DESCR", resultSetMapping = "AnEntity.implicit")
public class AnEntity{
@Id
private String code;
private String description;
@Column
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Column
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
from spring-data-commons.
Pavan Veeramachineni commented
What I was asking for in my earlier comment could be achieved by creating AnEntityRepository that extends Repository now that Repository does not extend any methods. So my earlier comment could be ignored & it may not be relevant for this issue either
from spring-data-commons.
Oliver Drotbohm commented
I am tempted to close this one as "works as designed" :). In my previous comment I already outlined how to set up a base repository interface with just the methods exposed you want to be exposed. Pavan's question for executing named native queries works out of the box as well as long as you follow the naming conventions correctly. Be aware that for the query execution the return type of the method might override the class level domain type. So something like this is perfectly possible:
public interface UserRepository extends MyCommonRepository<User, Long> {
List<UserDto> findUsersWithSpecialView(String foo, String bar);
}
@Entity
@SqlResultSetMapping(name = "UserDto.mapping", entities = @EntityResult(entityClass = UserDto.class))
@NamedNativeQuery(name = "User.findUsersWithSpecialView", query = "…", resultSetMapping = "UserDto.mapping")
public class User {
}
public class UserDto { … }
from spring-data-commons.
Pavan Veeramachineni commented
I tried introducing an intermediate interface that selectively exposes only finder related methods but to get it working I had to provide an implementation & a custom repository factory. The implementation is just a sub class of SimpleJpaRepository without any real functionality. The relevant code is attached. Without the factory & the implementation I kept getting the following exception:
Caused by: java.lang.IllegalArgumentException: No property exists found for type class com.company.app.pkg.Entity
at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76)
at org.springframework.data.repository.query.parser.Property.<init>(Property.java:97)
at org.springframework.data.repository.query.parser.Property.create(Property.java:312)
at org.springframework.data.repository.query.parser.Property.create(Property.java:292)
at org.springframework.data.repository.query.parser.Property.from(Property.java:251)
at org.springframework.data.repository.query.parser.Property.from(Property.java:232)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:48)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:242)
at org.springframework.data.repository.query.parser.PartTree.buildTree(PartTree.java:101)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:77)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:55)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:102)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:178)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:74)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:293)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:147)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:109)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:38)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 59 more
Two questions:
- Does the intermediate interface require an implementation even though it is not doing anything.
- This approach still does not seem like a clean design because even though the intermediate interface is only selectively exposing a few methods, the implementation still exposes all the methods. So the concrete interface can expose an unwanted method & still get the implementation.
Your Thoughts?
from spring-data-commons.
Oliver Drotbohm commented
No, the intermediate interface does not require any additional implementation code. It's only crucial that you copy the method signatures 1:1. Could you please show the intermediate interface you came up with to diagnose the error message in a bi more detail?
from spring-data-commons.
Pavan Veeramachineni commented
Sorry, forgot to mention in my earlier comment. The relevant files are attached
from spring-data-commons.
Oliver Drotbohm commented
Alright, it seems the documentation is lacking a tiny little but important detail. Here's the trick: as you probably have the namespace element configured to pickup this intermediate interface as well we will try to create a repository instance for that intermediate interface which is of course not what you want. So annotating that intermediate interface with @NoRepositoryBean
should exclude it from being found.
A potential concrete subinterface FooRepository extends ReadOnlyRepository<Foo, Long>
should be picked up correctly. No need to create any implementation code at all
from spring-data-commons.
Pavan Veeramachineni commented
I think i.e. in the documentation somewhere & I tried that as well. Still get the same exception. Here is my relevant spring config, change to the repository & the stack trace.
Spring Config fragment:
<jpa:repositories base-package="com.mycompany.repository"
entity-manager-factory-ref="entityManagerFactory"/>
ReadOnlyRepository change:
@NoRepositoryBean
public interface ReadOnlyRepository<T, ID extends Serializable> extends Repository<T, ID> {
Stacktrace:
Caused by: java.lang.IllegalArgumentException: No property exists found for type class <Entity>
at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76)
at org.springframework.data.repository.query.parser.Property.<init>(Property.java:97)
at org.springframework.data.repository.query.parser.Property.create(Property.java:312)
at org.springframework.data.repository.query.parser.Property.create(Property.java:292)
at org.springframework.data.repository.query.parser.Property.from(Property.java:251)
at org.springframework.data.repository.query.parser.Property.from(Property.java:232)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:48)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:242)
at org.springframework.data.repository.query.parser.PartTree.buildTree(PartTree.java:101)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:77)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:55)
from spring-data-commons.
Oliver Drotbohm commented
What does the concrete repository interface look like you're trying to get create an instance for?
from spring-data-commons.
Pavan Veeramachineni commented
Here is one without any methods that fails:
public interface StatusRepository extends ReadOnlyRepository<Status, Long> {
}
from spring-data-commons.
Oliver Drotbohm commented
I just pushed a fix to Spring Data Commons and it should be available in the snapshot repository in a few minutes. I moved the ticket into the Spring Data Commons project as well as the fix actually touches that codebase.
We only had test cases for concrete repository interfaces redeclaring the CRUD methods. Using an intermediate one the method matching algorithm didn't correctly match up the generics information which is now fixed. I've used some of your attached files to come up with test cases as you can see in the fixing commit.
Thanks a lot for the patience and time invested to help reproducing the issue!
from spring-data-commons.
Pavan Veeramachineni commented
Thanks for fixing this quickly! We do not have access to the snapshot repositories through our nexus servers. So I will have to install the jars locally & give it a shot. I will report back my results.
On another note it would be really nice if the implementation throws an exception when any concrete interface of this read-only repository defines a save method. I suppose I can do this with a custom implementation that overrides the save method
from spring-data-commons.
Pavan Veeramachineni commented
Works as expected with the latest build. Thanks!
from spring-data-commons.
Related Issues (20)
- Suggestion: Increases readability of `PageableExecutionUtils` code HOT 6
- DTO projection properties mapping to associations are not propulated
- Release 3.2.8 (2023.1.8)
- Release 3.3.2 (2024.0.2)
- using @EnableSpringDataWebSupport with spring-data-rest results in BeanDefinitionOverrideException HOT 1
- `KotlinBeanInfoFactory.getBeanInfo` throws exception when introspecting getter on value class HOT 4
- Switch to Broadcom docker proxy
- Investigate registering the target type of reading converters as simple types
- Kotlin lazy property identified as persistent entity HOT 4
- WarningMixing/WrappingMixing in PageModule overrides user defined Jackson annotations. HOT 2
- ConcurrentModificationException for registerEvent in TransactionalEventListener HOT 4
- @EnableSpringDataWebSupport not working in native image HOT 2
- Conversion of jMolecules `Identifier` implementations to primitive fails with Spring Data JDBC HOT 7
- PageableHandlerMethodArgumentResolverSupport still uses page, size as the default parameter names
- Property path with whitespace inconsistently throws exception HOT 2
- Release 3.2.9 (2023.1.9)
- Release 3.3.3 (2024.0.3)
- Introduce `Parameter.getRequiredName()` method
- Custom Repository returns `Optional` as return type for `T` HOT 1
- Thread Pinning in `Repositories#cacheRepositoryFactory()` HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from spring-data-commons.