crnk-project / crnk-framework

JSON API library for Java
Apache License 2.0
289 stars 154 forks source link

Repository initialization issue with computed attributed #470

Open JochenReinhardt opened 5 years ago

JochenReinhardt commented 5 years ago

Another one: I noticed strange errors in my integration tests that only occurred under certain conditions, e.g. when executing a single test. I have created a demo application to reproduce the issue: https://github.com/JochenReinhardt/crnk-jpa-dto-demo/tree/master/crnk-jpa-computed-value-demo

There I have two entities, one of them with a computed attribute, the other one plain. When the computed repository is queried first after application startup, everything works fine. But if the plain repository is queried first, I get an exception:

java.lang.IllegalStateException: meta element not found for class io.crnk.demo.jpa.computedvalue.computed.ComputedEntity
    at io.crnk.core.engine.internal.utils.PreconditionUtil.fail(PreconditionUtil.java:50) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.utils.PreconditionUtil.verify(PreconditionUtil.java:131) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.meta.provider.MetaPartitionBase.getMeta(MetaPartitionBase.java:44) ~[crnk-meta-2.11.20190113153635.jar:na]
    at io.crnk.meta.internal.BaseMetaPartition.getMeta(BaseMetaPartition.java:54) ~[crnk-meta-2.11.20190113153635.jar:na]
    at io.crnk.meta.provider.MetaPartitionBase.getMeta(MetaPartitionBase.java:42) ~[crnk-meta-2.11.20190113153635.jar:na]
    at io.crnk.jpa.internal.query.ComputedAttributeRegistryImpl$Registration.getAttribute(ComputedAttributeRegistryImpl.java:79) ~[crnk-jpa-2.11.20190113153635.jar:na]
    at io.crnk.jpa.internal.query.ComputedAttributeRegistryImpl.getForType(ComputedAttributeRegistryImpl.java:54) ~[crnk-jpa-2.11.20190113153635.jar:na]
    at io.crnk.jpa.JpaEntityRepositoryBase.findAll(JpaEntityRepositoryBase.java:88) ~[crnk-jpa-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.repository.ResourceRepositoryAdapterImpl$2.invoke(ResourceRepositoryAdapterImpl.java:91) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.repository.ResponseRepositoryAdapter$RepositoryRequestFilterChainImpl.doFilter(ResponseRepositoryAdapter.java:233) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.repository.ResourceRepositoryAdapterImpl.findAll(ResourceRepositoryAdapterImpl.java:101) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.dispatcher.controller.CollectionGetController.handleAsync(CollectionGetController.java:42) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.dispatcher.controller.BaseController.handle(BaseController.java:58) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.core.engine.internal.http.DocumentFilterChainImpl.doFilter(DocumentFilterChainImpl.java:28) ~[crnk-core-2.11.20190113153635.jar:na]
    at io.crnk.jpa.JpaModule$4$1.call(JpaModule.java:407) ~[crnk-jpa-2.11.20190113153635.jar:na]

It seems, the plain repository somehow relies on the computed repository to be fully initialized. But this is not always the case. The plain repository starts working only after the computed repository is accessed.

Why is the JpaRepository for the plain repository looking for meta elements of a completely unrelated resource? I also noticed the computed attribute example has been removed from the latest documentation. Are you going to remove this feature in the future?

remmeier commented 5 years ago

I have no Maven setup as of yet, but the attachd commit should fix it. Otherwise I can look more closely. And have to setup a test to verify it. The build should run through within the next 20 minutes and publish to the latest repository (https://travis-ci.org/crnk-project/crnk-framework/branches).

In general the new JpaEntityRepositoryBase allows to perform any kind of customization. And relationships are forward to the resource repositories. It allows to have a simpler/more flexible setup. And DB views can give simlar functionality to the the computed attributes. With this in mind I think the use case for the original DTO mapping is shrinking. It continues to be supported and has its use cases. But so far have seen a bit too much confusing in the area. And the JpaModule has been rather old based on old assumptions that no longer hold. So it got a bit of a rewrite. In your case it caused a bit of trouble, sorry for that. An official 2.12 will follow in the coming days with this and some other things.

JochenReinhardt commented 5 years ago

DTO mappings and computed attributes were one of my main reasons to start using crnk. I am building an internally used API for a very complex, historically grown JEE based application. The existing persistence layer is the foundation of the hole application. I do not want to touch it (e.g. by adding crnk or JSON annotations) as it is used throughout the application and the crnk based API is only one of the users.

I do not particularly like the idea of database views. I don't like to have crnk-interface related issues punch straigth through into the database. I would have to create dozens of views, many of them have to be updateable and there are lot's of relations to take care of. The DTO approach seems to be much more lightweight. I understand that DTO mapping creates a lot of complexity for crnk itself, though.

remmeier commented 5 years ago

Complexity in crnk is now actually quite minimal. And the dto mapping use case is perfectly valid. I'm just trying to get people use it only when necessary and recommend the potential alternatives when possible.I will do a new example in crnk-example with the new JPA module approach as that is so far missing, maybe with some advanced save/delete. Should you already have something, that would be appreciated as well.

BTW: there is also

@Entity
@Subselect(...)

It is close to the views but without touching the database. For Hibernate at least.