forked from sboesebeck/morphium
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add morphium-jakarta-data as optional module #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Bardioc1977
wants to merge
14
commits into
master
Choose a base branch
from
pr/jakarta-data-module
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
9c52cea
feat: add morphium-jakarta-data as optional module
flgke81 5940511
build: register morphium-jakarta-data in extensions profile
flgke81 4398414
docs: add jakarta data module documentation
flgke81 09d6c1c
docs: add changelog entry for morphium-jakarta-data module
flgke81 cdc468c
build: include morphium-jakarta-data in release bundle
flgke81 9dc86b0
fix(jakarta-data): reject mixed And/Or method names and non-upserting…
flgke81 cf4f72e
fix(jakarta-data): correct CONTAINS substring match, delete() count, …
flgke81 420725a
fix(jakarta-data): correct cursor pagination sort sources and OFFSET-…
flgke81 c7aa6f3
fix(jakarta-data): fix JDQL ORDER BY without WHERE, HAVING-without-GR…
flgke81 a80d5d5
fix(jakarta-data): validate unknown fields in derived query methods a…
flgke81 9fb2d0c
fix(jakarta-data): require non-empty sort keyset for cursor pagination
flgke81 cb9950f
fix(jakarta-data): fall back to bridge classloader when loading GROUP…
flgke81 e79de9f
fix(jakarta-data): make NOT_CONTAINS a negated substring match, not e…
flgke81 b72898d
fix(jakarta-data): escape and anchor JDQL LIKE patterns like the deri…
flgke81 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Changelog | ||
|
|
||
| All notable changes to this project will be documented in this file. | ||
|
|
||
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). | ||
|
|
||
| ## [Unreleased] | ||
|
|
||
| ### Changed | ||
|
|
||
| #### Integrated as a module of the Morphium multi-module project | ||
| `morphium-jakarta-data` is no longer a standalone Maven project with its own release cycle. It is now built as a module of the Morphium multi-module reactor (`morphium-parent`), lives in the `morphium-jakarta-data/` directory of the [sboesebeck/morphium](https://github.com/sboesebeck/morphium) repository, and is versioned in lockstep with Morphium core. The artifact coordinates changed from `de.caluga:morphium-jakarta-data:1.1.0` (standalone) to `de.caluga:morphium-jakarta-data:<morphium-version>` (currently `6.2.6-SNAPSHOT`). The groupId is unchanged. Existing users pinning `1.1.0`/`1.1.0-SNAPSHOT` (or the earlier `1.0.0-SNAPSHOT` line) need to bump the dependency version to match the Morphium core version they use, and should expect the artifact to be built from the Morphium reactor going forward — this repository is archived once the migration completes. No source-level API changes are part of this move; only the build/versioning model changed. | ||
|
|
||
| ## [1.1.0-SNAPSHOT] (superseded — see [Unreleased]) | ||
|
|
||
| This heading previously read `[Unreleased] - 1.0.0-SNAPSHOT`, which no longer reflected reality: the module had already moved past `1.0.0-SNAPSHOT` to `1.1.0-SNAPSHOT` as a standalone project before the integration into Morphium made a fixed pre-1.0 standalone version number moot altogether. The entries below are kept for history; going forward, changes are tracked under `[Unreleased]` above and, once released, under the Morphium version they ship with. | ||
|
|
||
| ### Added | ||
| - Framework-agnostic Jakarta Data 1.0 runtime for Morphium ODM | ||
| - `AbstractMorphiumRepository` base class with full CRUD implementation | ||
| - `MorphiumRepository` extended interface (distinct, direct Morphium/Query access) | ||
| - Query derivation from method names: `findBy*`, `countBy*`, `existsBy*`, `deleteBy*` | ||
| - Supported operators: equals, greaterThan, lessThan, like, in, between, not, and, or | ||
| - JDQL parsing via `@Query` annotation | ||
| - `@Find` / `@Delete` with `@By` parameter binding | ||
| - Pagination support: `Page<T>`, `CursoredPage<T>`, `PageRequest` | ||
| - Sorting: `Sort<T>`, `Order<T>`, `@OrderBy` | ||
| - Stream and async return types: `Stream<T>`, `CompletionStage<T>` | ||
| - `RepositoryMetadata` for entity type, ID type, and collection name resolution |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| # Morphium Jakarta Data | ||
|
|
||
| An optional module of [Morphium](https://github.com/sboesebeck/morphium), the MongoDB ODM and messaging framework for Java 21+. This module provides a framework-agnostic [Jakarta Data 1.0](https://jakarta.ee/specifications/data/1.0/) runtime — repository implementation, query derivation, JDQL parsing, pagination, and sorting — on top of Morphium. | ||
|
|
||
| ## What this module is and is not | ||
|
|
||
| `morphium-jakarta-data` is the shared implementation layer that turns Jakarta Data repository interfaces into Morphium queries. It has **zero framework dependencies**: only Morphium core and the Jakarta Data API. | ||
|
|
||
| Application code typically does **not** depend on this module directly. Instead, it goes through a framework integration: | ||
|
|
||
| | Framework | Module | Repository generation | | ||
| |-----------|--------|------------------------| | ||
| | Quarkus | `quarkus-morphium` | Gizmo bytecode generation (build-time) | | ||
| | Spring Boot | `spring-boot-morphium` | JDK dynamic proxies (runtime) | | ||
|
|
||
| This module exists as a separate artifact so the ~2400 lines of query derivation, JDQL parsing, pagination, and result-type handling are implemented once and shared, instead of being duplicated between the Quarkus and Spring Boot adapters. | ||
|
|
||
| The direct target audience for this module is anyone building their **own** framework integration — Micronaut, Helidon, plain Jakarta EE, or a hand-rolled repository wiring in plain Java. If that is not your situation, use `quarkus-morphium` or `spring-boot-morphium` instead and treat this module as an implementation detail. | ||
|
|
||
| ## Optionality | ||
|
|
||
| Morphium core (`de.caluga:morphium`) does **not** depend on this module. Projects that only pull in `de.caluga:morphium` get the ODM, driver, caching, and messaging — but no `jakarta.data-api` dependency and no repository support. Jakarta Data support is opt-in by adding `morphium-jakarta-data` (directly, or transitively via one of the framework integrations). | ||
|
|
||
| ## Features | ||
|
|
||
| - `CrudRepository<T, K>` and `MorphiumRepository<T, K>` base interfaces | ||
| - Query derivation from method names: `findBy*`, `countBy*`, `existsBy*`, `deleteBy*` | ||
| - Supported operators: equals, greaterThan, lessThan, like, in, between, not, and, or | ||
| - JDQL (Jakarta Data Query Language) support via `@Query` annotation | ||
| - `@Find` / `@Delete` with `@By` parameter binding | ||
| - Pagination: `Page<T>`, `CursoredPage<T>`, `PageRequest` | ||
| - Sorting: `Sort<T>`, `Order<T>`, `@OrderBy` | ||
| - Stream and async return types: `Stream<T>`, `CompletionStage<T>` | ||
| - `RepositoryMetadata` for entity type, ID type, and collection name resolution | ||
|
|
||
| ## Maven Dependency | ||
|
|
||
| ```xml | ||
| <dependency> | ||
| <groupId>de.caluga</groupId> | ||
| <artifactId>morphium-jakarta-data</artifactId> | ||
| <version>${project.version}</version> <!-- currently 6.2.6-SNAPSHOT --> | ||
| </dependency> | ||
| ``` | ||
|
|
||
| The version tracks Morphium's version lockstep — `morphium-jakarta-data` is released alongside `morphium` core with the same version number, not independently. | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| morphium-jakarta-data | ||
| de.caluga.morphium.data | ||
| AbstractMorphiumRepository Core CRUD implementation (protected setMorphium) | ||
| MorphiumRepository Extended repository interface (distinct, query access) | ||
| RepositoryMetadata Entity type, ID type, collection name metadata | ||
| QueryDescriptor Parsed query representation (field, operator, value) | ||
| MethodNameParser Parses findByXxx method names into QueryDescriptors | ||
| JdqlParser / JdqlQuery JDQL (Jakarta Data Query Language) parsing | ||
| QueryMethodBridge Executes derived queries (findBy*, countBy*, deleteBy*) | ||
| JdqlMethodBridge Executes @Query JDQL methods | ||
| FindMethodBridge Executes @Find / @Delete annotated methods | ||
| QueryExecutor Low-level Morphium query execution | ||
| QueryResultHelper Result type adaptation (List, Stream, Page, Optional) | ||
| CursorHelper Cursor-based pagination support | ||
| SortMapper Maps Jakarta Data Sort/Order to Morphium sort | ||
| MorphiumPage Page/CursoredPage implementation | ||
| ``` | ||
|
|
||
| ### Processing chain | ||
|
|
||
| A repository method call is resolved through a fixed pipeline, regardless of which bridge parses it: | ||
|
|
||
| ``` | ||
| Repository method call | ||
| -> MethodNameParser (findBy*/countBy*/...) or JdqlParser (@Query / JDQL) | ||
| -> QueryDescriptor (parsed field/operator/value/sort representation) | ||
| -> QueryExecutor (builds and runs the Morphium Query<T>) | ||
| -> QueryResultHelper (adapts the raw result to the declared return type) | ||
| -> return type (T, Optional<T>, List<T>, Stream<T>, Page<T>, CursoredPage<T>, CompletionStage<T>, ...) | ||
| ``` | ||
|
|
||
| `@Find` / `@Delete` methods go through `FindMethodBridge` instead of `MethodNameParser`, but join the same `QueryDescriptor` → `QueryExecutor` → `QueryResultHelper` chain from that point on. | ||
|
|
||
| The key design point is `AbstractMorphiumRepository.setMorphium(Morphium)` being `protected` — framework subclasses override it to bridge their injection mechanism: | ||
| - Quarkus: `@Inject` + `@PostConstruct` | ||
| - Spring Boot: public setter called by `FactoryBean` | ||
|
|
||
| ## Building your own framework integration | ||
|
|
||
| To wire a new framework to this module, extend `AbstractMorphiumRepository<T, K>` for each repository interface and call `setMorphium(Morphium)` once a `Morphium` instance is available from your framework's dependency injection (or from plain code). The repository interface methods delegate to the `doXxx()` methods already implemented on `AbstractMorphiumRepository`; for query-derivation and JDQL methods not covered by the base class, dispatch through `QueryMethodBridge` / `JdqlMethodBridge` / `FindMethodBridge` as needed. | ||
|
|
||
| Minimal example without any framework, wiring a repository by hand: | ||
|
|
||
| ```java | ||
| import de.caluga.morphium.Morphium; | ||
| import de.caluga.morphium.data.AbstractMorphiumRepository; | ||
| import de.caluga.morphium.data.RepositoryMetadata; | ||
|
|
||
| public class PersonRepositoryImpl extends AbstractMorphiumRepository<Person, String> | ||
| implements PersonRepository { | ||
|
|
||
| public PersonRepositoryImpl(Morphium morphium) { | ||
| super(new RepositoryMetadata(Person.class, String.class, "id")); | ||
| setMorphium(morphium); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Person> findById(String id) { | ||
| return doFindById(id); | ||
| } | ||
|
|
||
| @Override | ||
| public List<Person> findAll() { | ||
| return doFindAll().toList(); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| `setMorphium(Morphium)` is `protected`, so it can only be called from within the class hierarchy — subclasses either widen its visibility (as Spring Boot's public setter does) or call it internally from a constructor/lifecycle callback (as the example above and the Quarkus `@PostConstruct` integration do). | ||
|
|
||
| ## Building | ||
|
|
||
| This module is part of the Morphium multi-module Maven build. Build it from the root of the `morphium` repository: | ||
|
|
||
| ```bash | ||
| mvn -pl morphium-jakarta-data -am verify | ||
| ``` | ||
|
|
||
| `-am` (also-make) ensures `morphium-core` is built first if it is not already up to date in the reactor. | ||
|
|
||
| ## Requirements | ||
|
|
||
| | Requirement | Version | | ||
| |-------------|---------| | ||
| | Java | 21+ | | ||
| | Morphium | same version (lockstep) | | ||
| | Jakarta Data API | 1.0 | | ||
|
|
||
| ## License | ||
|
|
||
| This module is licensed under the same terms as the Morphium project (Apache License 2.0). There is no separate license file for this module — the license is defined at the repository root of the Morphium project. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <!-- ENTSCHEIDUNG-OFFEN D1: Lockstep mit Morphium-Version. Bei Variante A (eigene Versionslinie) hier <version> und <morphium.version> ergänzen. --> | ||
| <parent> | ||
| <groupId>de.caluga</groupId> | ||
| <artifactId>morphium-parent</artifactId> | ||
| <version>6.3.0-SNAPSHOT</version> | ||
| </parent> | ||
| <artifactId>morphium-jakarta-data</artifactId> | ||
| <packaging>jar</packaging> | ||
| <name>Morphium Jakarta Data</name> | ||
| <description>Framework-agnostic Jakarta Data runtime for Morphium ODM</description> | ||
| <dependencies> | ||
| <dependency> | ||
| <groupId>de.caluga</groupId> | ||
| <artifactId>morphium</artifactId> | ||
| <version>${project.version}</version> | ||
| </dependency> | ||
| <!-- jakarta.data.version and dependencyManagement now inherited from morphium-parent --> | ||
| <dependency> | ||
| <groupId>jakarta.data</groupId> | ||
| <artifactId>jakarta.data-api</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> | ||
| </dependency> | ||
| <!-- Test --> | ||
| <!-- M2: prüfen ob nach morphium-parent --> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter</artifactId> | ||
| <version>5.10.2</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.assertj</groupId> | ||
| <artifactId>assertj-core</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>ch.qos.logback</groupId> | ||
| <artifactId>logback-classic</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| <build> | ||
| <sourceDirectory>src/main/java</sourceDirectory> | ||
| <testSourceDirectory>src/test/java</testSourceDirectory> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-surefire-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-source-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-javadoc-plugin</artifactId> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-jar-plugin</artifactId> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: Bardioc1977/morphium
Length of output: 6539
🏁 Script executed:
Repository: Bardioc1977/morphium
Length of output: 17693
🏁 Script executed:
Repository: Bardioc1977/morphium
Length of output: 8399
🌐 Web query:
Jakarta Data 1.0 BasicRepository findAll Stream<T> signature CrudRepository💡 Result:
In Jakarta Data 1.0, the
BasicRepository<T, K>interface defines thefindAll()method with the following signature [1]:@FindStream findAll; This method retrieves all persistent entities of the specified type from the database and returns aStream<T>[1][2]. It is important to note that this method will never returnnull, though it may throw anUnsupportedOperationExceptionif the underlying database (such as certain Key-Value or Wide-Column stores) is not capable of performing thefindAlloperation [1][3]. TheCrudRepository<T, K>interface extendsBasicRepository<T, K>[4][5]. Consequently, any repository interface that extendsCrudRepositoryinherits thisfindAll()method signature [4].Citations:
Return
Stream<Person>forfindAll()in the example.PersonRepositoryImplclaims@Override, but@Find Stream<T> findAll()is the Jakarta Data contract. AList<Person>method is an overload, not an override, so any generated/proxiedfindAll()call is left unimplemented.Proposed contract-aligned example
Add
java.util.stream.Streamto the omitted imports.📝 Committable suggestion
🤖 Prompt for AI Agents