devonfw-forge / devonfw-microservices

Apache License 2.0
2 stars 7 forks source link

Evaluate spring-data on quarkus #37

Closed hohwille closed 3 years ago

hohwille commented 3 years ago

As a user of devon4j I want to use spring-data-jpa in my quarkus app. Within this story, you should evaluate using spring-data-jpa in a quarkus app.

IMHO it would make sense to create a feature branch from our sample app and port it to spring-data-jpa replacing DAOs (https://github.com/devonfw-forge/devonfw-microservices/blob/main/reference-project/src/main/java/com/devonfw/demoquarkus/domain/dao/AnimalDAO.java) with Repositories.

devon4j documentation of repositories with sample code: https://github.com/devonfw/devon4j/blob/master/documentation/guide-repository.asciidoc#repository

For the record: This is the issue where and why we introduced spring-data in oasp4j (pre-decessor of devon4j): https://github.com/oasp/oasp4j/issues/626

GuentherJulian commented 3 years ago

Created a feature branch of the reference project with Spring Data Integration, where I replaced the DAOs with the repository concept of Spring Data. Tested it in both native and normal JVM mode. Link to the Quarkus Spring Data guide: https://quarkus.io/guides/spring-data-jpa

To implement a repository the interface has to extend one of the following Spring Data repositories (see the example):

These Spring Data Repositories provide some basic implementations for accessing data. For example, the CrudRepository interface provides methods for returning all instances of a type (findAll) or returning an instance by its ID (findById). Methods of repository interfaces that follow Spring Data conventions are implemented automatically. This means that you do not have to write code for them. Examples:

You can customize your repository to add additional functionality or override the default implementations by using repository fragments: https://github.com/devonfw-forge/devonfw-microservices/blob/feature/spring_data/reference-project/src/main/java/com/devonfw/demoquarkus/domain/repo/AnimalFragmentImpl.java

Features

@Query annotations The Quarkus Spring Data extension supports the definition of static PSQL queries with the @Query annotation (see example here). Native and named queries are not supported using @Query annotation. You will recieve something like Build step io.quarkus.spring.data.deployment.SpringDataJPAProcessor#build threw an exception: java.lang.IllegalArgumentException: Attribute nativeQuery of @Query is currently not supported.

Criteria API Quarkus supports the use of the Criteria API in both native and JVM mode to define dynamic queries (see example here).

QueryDSL QuerySQL, contrary to what is claimed in the Quarkus Spring Data guide, works in both native and JVM mode to define dynamic queries (see example here).

Pagination Quarkus Spring Data offers paging support. Unfortunately, this only seems to be fully functional in JVM mode. In JVM mode the content and page information is returned, but in native mode only the content is returned.

JVM mode:

{
    "content": [
        {
            "id": 1,
            "name": "...",
            ...
        },
        ...
    ],
    "pageable": "...",
    "last": ...,
    "totalPages": ...,
    "totalElements": ...,
    "size": ...,
    "number": ...,
    "sort": {
        "sorted": ...,
        "unsorted": ...,
        "empty": ...
    },
    "first": ...,
    "numberOfElements": ...,
    "empty": ...
}

Native mode:

{
    "totalPages": ...
    "totalElements": ... 
}
hohwille commented 3 years ago

@GuentherJulian thank you for your testing and feedback. This is exactly what we need and what I requested with this issue. Great work 👍

So the great news is that it is working and supported in general not only in JVM mode but also in native image. To summarize the limitations (at least in native image):

Is that sufficient for a real-world project production usage? Yes and no! Yes as it is what you need to get started. But no as paging support is mandatory and native queries are important for performance tuning options in real world scenarios. So IMHO we should get in touch with the dev teams and see if we can get some details about the status:

I think this is all an excellent starting point to create documentation about spring-data support as a guide. The "status" (incomplete features / limitations) should be a separate section. Ideally with our approach to get in touch we should try to figure out according issues in the projects that indicate the story for the lacking feature and makes the implementation status transparent. Then we can simply link to such issue. This allows everybody to track the status even if our documentation is not updated fast enough and also gives developers the chance to connect or even contribute to make it happen.

hohwille commented 3 years ago

One further request: It is best practice to use named parameters instead of indexed parameters: https://github.com/devonfw-forge/devonfw-microservices/blob/d9bc758fd9c9076a06fea5abf3f3851d451c597f/reference-project/src/main/java/com/devonfw/demoquarkus/domain/repo/AnimalRepository.java#L11 So instead of ?1 use :name and annotate parameter with @Param. This is especially benefitial when using multiple parameters or especially when the same parameter is used multiple times what is all a mess with indexed parameters. Also indexed parameters always cause confusion and errors as they are 1-based while in development typically indexes are 0-based.

See also the devon4j guide: https://github.com/devonfw/devon4j/blob/master/documentation/guide-repository.asciidoc#example

GuentherJulian commented 3 years ago

One further request: It is best practice to use named parameters instead of indexed parameters: https://github.com/devonfw-forge/devonfw-microservices/blob/d9bc758fd9c9076a06fea5abf3f3851d451c597f/reference-project/src/main/java/com/devonfw/demoquarkus/domain/repo/AnimalRepository.java#L11

So instead of ?1 use :name and annotate parameter with @Param. This is especially benefitial when using multiple parameters or especially when the same parameter is used multiple times what is all a mess with indexed parameters. Also indexed parameters always cause confusion and errors as they are 1-based while in development typically indexes are 0-based. See also the devon4j guide: https://github.com/devonfw/devon4j/blob/master/documentation/guide-repository.asciidoc#example

Changed it to named parameter

GuentherJulian commented 3 years ago

Evalutation is done. Documentation will be created with this task https://github.com/devonfw/devon4quarkus/issues/19

GuentherJulian commented 3 years ago

Rechecked the Paging support: Using the Page<T> interface (Page documention) as the return type in the rest service, the response in native mode would look like the following:

{
    "totalPages": ...
    "totalElements": ... 
}

In JVM mode all page information is returned, but in native mode only the totalPages and totalElements properties can be derived from the interface.

To make it work in native mode, PageImpl<T> has to be used as the return type. Then the responses in JVM and native mode are the same.

Conclusion: Paging is supported in both native and JVM mode

hohwille commented 3 years ago

Conclusion: Paging is supported in both native and JVM mode

Great to hear that.

For native queries I created issue #45 as this issue is already closed.