Skip to content

Commit

Permalink
Merge pull request #211 from xdev-software/develop
Browse files Browse the repository at this point in the history
v2.4.1
  • Loading branch information
JohannesRabauer authored Dec 19, 2024
2 parents 7fb7dba + 9b44843 commit a5d4b73
Show file tree
Hide file tree
Showing 24 changed files with 361 additions and 93 deletions.
1 change: 0 additions & 1 deletion .idea/saveactions_settings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 2.4.1

* Updated EclipseStore to v2.1.0
* Added EclipseStore-Rest-API to tests (storage-restservice-springboot)

# 2.4.0

* Updated org.springframework.boot.version to v3.4.0
Expand All @@ -8,6 +13,7 @@

* Auto-Fix problems with adding ids to entities with existing data store.

~~~~
# 2.3.0
* Add support for shutting down the storage during application shutdown
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ instructions** are in the documentation](https://xdev-software.github.io/spring-
| ``1.0.8-1.0.10`` | ``17`` | ``3.3.1`` | ``1.3.2`` |
| ``2.0.0-2.1.0`` | ``17`` | ``3.3.2`` | ``1.4.0`` |
| ``2.2.0-2.3.1`` | ``17`` | ``3.3.4`` | ``1.4.0`` |
| ``>= 2.4.0`` | ``17`` | ``3.4.0`` | ``2.0.0`` |
| ``2.4.0`` | ``17`` | ``3.4.0`` | ``2.0.0`` |
| ``>= 2.4.1`` | ``17`` | ``3.4.0`` | ``2.1.0`` |

## Demo

Expand Down
48 changes: 48 additions & 0 deletions assets/DependingClasses.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" version="25.0.3">
<diagram name="Page-1" id="6GyipOatxIIVSVKHxFAy">
<mxGraphModel dx="1562" dy="845" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="hvzIIKVZ51MqT405g5E5-15" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=none;" vertex="1" parent="1">
<mxGeometry x="150" y="120" width="430" height="250" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-5" value="" style="group" vertex="1" connectable="0" parent="1">
<mxGeometry x="440" y="140" width="100" height="100" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-3" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=none;strokeColor=#D62125;strokeWidth=3;align=center;verticalAlign=middle;fontFamily=Helvetica;fontSize=12;fontColor=default;" vertex="1" parent="hvzIIKVZ51MqT405g5E5-5">
<mxGeometry x="20" y="20" width="60" height="80" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-4" value="&lt;span style=&quot;font-weight: 400; text-wrap-mode: wrap;&quot;&gt;ArticleRepository&lt;/span&gt;" style="text;strokeColor=none;fillColor=none;html=1;fontSize=15;fontStyle=1;verticalAlign=middle;align=center;" vertex="1" parent="hvzIIKVZ51MqT405g5E5-5">
<mxGeometry y="-10" width="100" height="20" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-6" value="" style="group" vertex="1" connectable="0" parent="1">
<mxGeometry x="190" y="140" width="100" height="100" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-1" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fillColor=none;strokeColor=#D62125;strokeWidth=3;" vertex="1" parent="hvzIIKVZ51MqT405g5E5-6">
<mxGeometry x="20" y="20" width="60" height="80" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-2" value="&lt;span style=&quot;font-weight: 400; text-wrap-mode: wrap;&quot;&gt;OrderRepository&lt;/span&gt;" style="text;strokeColor=none;fillColor=none;html=1;fontSize=15;fontStyle=1;verticalAlign=middle;align=center;" vertex="1" parent="hvzIIKVZ51MqT405g5E5-6">
<mxGeometry y="-10" width="100" height="20" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-7" value="&lt;font&gt;Order&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;fontSize=15;fillColor=none;strokeColor=#D62125;strokeWidth=3;align=center;verticalAlign=middle;fontFamily=Helvetica;fontColor=default;" vertex="1" parent="1">
<mxGeometry x="180" y="290" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-8" value="&lt;font&gt;Article&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;fontSize=15;fillColor=none;strokeColor=#D62125;strokeWidth=3;align=center;verticalAlign=middle;fontFamily=Helvetica;fontColor=default;" vertex="1" parent="1">
<mxGeometry x="430" y="290" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-16" value="" style="shape=flexArrow;endArrow=classic;startArrow=none;html=1;rounded=0;strokeColor=#C91F24;strokeWidth=2;fillColor=default;startFill=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="hvzIIKVZ51MqT405g5E5-7" target="hvzIIKVZ51MqT405g5E5-8">
<mxGeometry width="100" height="100" relative="1" as="geometry">
<mxPoint x="320" y="470" as="sourcePoint" />
<mxPoint x="480" y="470" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="hvzIIKVZ51MqT405g5E5-20" value="&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;; font-size: 15px; font-weight: 700;&quot;&gt;@OneToMany&lt;/span&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="hvzIIKVZ51MqT405g5E5-16">
<mxGeometry x="0.21" relative="1" as="geometry">
<mxPoint x="-17" y="-30" as="offset" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
6 changes: 3 additions & 3 deletions docs/antora.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
name: ROOT
title: Spring-Data-Eclipse-Store
version: master
display_version: '2.4.0'
display_version: '2.4.1'
start_page: index.adoc
nav:
- modules/ROOT/nav.adoc
asciidoc:
attributes:
product-name: 'Spring-Data-Eclipse-Store'
display-version: '2.4.0'
maven-version: '2.4.0'
display-version: '2.4.1'
maven-version: '2.4.1'
page-editable: false
page-out-of-support: false
1 change: 1 addition & 0 deletions docs/modules/ROOT/assets/images/DependingClasses.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
** xref:features/queries.adoc[Queries]
** xref:features/transactions.adoc[Transactions]
** xref:features/versions.adoc[Versions]
** xref:features/rest-api.adoc[REST Interface]
* xref:migration.adoc[Migration from JPA]
* xref:known-issues.adoc[Known issues]
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/features/features.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
* xref:features/queries.adoc[Queries]
* xref:features/transactions.adoc[Transactions]
* xref:features/versions.adoc[Versions]
* xref:features/rest-api.adoc[REST Interface]
38 changes: 36 additions & 2 deletions docs/modules/ROOT/pages/features/lazies.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,46 @@ import software.xdev.spring.data.eclipse.store.repository.lazy.SpringDataEclipse
public class Owner extends Person
{
private String address;
//...
private final Lazy<List<Pet>> pets = SpringDataEclipseStoreLazy.build(new ArrayList<>());
//...
----

== FetchType.LAZY

In Spring JPA, lazy loading is achieved by annotating a field or property with ``FetchType.LAZY``.
This approach leverages JPA's built-in mechanisms to defer the retrieval of the related entity until it is accessed.

In contrast, {product-name} takes a different approach.
Instead of using annotations, you wrap the object intended to be loaded lazily in a ``Lazy``-wrapper.
This wrapper encapsulates the object and ensures it is only loaded when needed.

[source,java,title="JPA Example with lazy"]
----
import jakarta.persistence.OneToMany;
public class Owner extends Person
{
@OneToMany(fetch = FetchType.LAZY)
private final List<Pet> pets = new ArrayList<>();
//...
----

[source,java,title="https://github.com/xdev-software/spring-data-eclipse-store/tree/develop/spring-data-eclipse-store-demo/src/main/java/software/xdev/spring/data/eclipse/store/demo/complex/owner/Owner.java[Slightly changed example from complex demo]"]
----
package software.xdev.spring.data.eclipse.store.demo.complex.owner;
//...
import software.xdev.spring.data.eclipse.store.repository.lazy.SpringDataEclipseStoreLazy;
public class Owner extends Person
{
private final List<Lazy<Pet>> pets = new ArrayList<>();
//...
----

The ``Lazy``-wrapper makes lazy loading **explicit and flexible**, avoiding JPA-specific overhead and potential exceptions.
But it introduces a custom, less-standardized approach that may increase boilerplate and requires developers to remember to use the wrapper, which could lead to errors if overlooked.

== Repositories

Entities in a repository are by default **not lazy**.
Expand Down
55 changes: 55 additions & 0 deletions docs/modules/ROOT/pages/features/rest-api.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
= REST Interface

To utilize the https://docs.eclipsestore.io/manual/storage/rest-interface/index.html[REST interface provided by EclipseStore], only a small adjustment is needed.

First add the dependency described in the https://docs.eclipsestore.io/manual/storage/rest-interface/setup.html#_spring_boot_rest_service[EclipseStore documentation]:
[source,xml,subs=attributes+,title="Maven [pom.xml]"]
----
<dependencies>
<dependency>
<groupId>org.eclipse.store</groupId>
<artifactId>storage-restservice-springboot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
----
Next a few adjustments are needed in your configuration:
[source,java,title="https://github.com/xdev-software/spring-data-eclipse-store/blob/develop/spring-data-eclipse-store-demo/src/main/java/software/xdev/spring/data/eclipse/store/demo/complex/ComplexConfiguration.java[Example from complex demo]"]
----
package software.xdev.spring.data.eclipse.store.demo.complex;
//...
import org.eclipse.store.storage.restadapter.types.StorageRestAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreClientConfiguration;
import software.xdev.spring.data.eclipse.store.repository.config.EnableEclipseStoreRepositories;
@ComponentScan({"org.eclipse.store.storage.restservice.spring.boot.types.rest"})
@Configuration
@EnableEclipseStoreRepositories
public class ComplexConfiguration extends EclipseStoreClientConfiguration
{
//...
@Bean
@DependsOn({"embeddedStorageFoundationFactory"})
public Map<String, StorageRestAdapter> storageRestAdapters(final Map<String, EmbeddedStorageManager> storages)
{
return Map.of(
"defaultStorageManager", StorageRestAdapter.New(this.storageInstance.getInstanceOfStorageManager())
);
}
//...
----
After that the API is usable just like https://docs.eclipsestore.io/manual/storage/rest-interface/rest-api.html[plain EclipseStore].
The ``instance-name`` in this case would be ``default`` which means, the active URL in the ComplexDemo is ``http://localhost:8080/store-data/default/root``.
34 changes: 34 additions & 0 deletions docs/modules/ROOT/pages/known-issues.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,37 @@ This **should** handle most problems with the ClassLoader.
Restarting the storage leads to a reloading of all entities and may take some time, yet circumvents the Restart ClassLoader Issue.

The behavior can be configured through xref:configuration.adoc#context-close-shutdown-storage[Properties] and is implemented in the https://github.com/xdev-software/spring-data-eclipse-store/tree/develop/spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/config/EclipseStoreClientConfiguration.java[EclipseStoreClientConfiguration.java].

== Multiple Repositories with related entities [[multi-repos-with-related-entities]]

In SQL databases, relationships between entities are explicitly defined and enforced by the database system.
This ensures that constraints, such as foreign keys, are consistently maintained.

In contrast, relationships in a Java object graph are solely defined by the developer.
If an object within the graph does not maintain a reference back to its parent or containing object, it has no inherent knowledge of that relationship.
Consequently, finding such a relationship requires searching the entire object graph, which can be highly inefficient.

image::DependingClasses.svg[Example structure with orders and articles]

Example Scenario:
Consider an *order object* that contains references to several *article objects*.
In this case, determining which order contains a specific article is nearly impossible without traversing the entire object graph to locate it.
This lack of direct reference contrasts sharply with the behavior of SQL databases.

What Happens When an Article is Deleted?

1. In an *SQL Database*: +
Attempting to delete an article that is still referenced (e.g., by an order) would typically result in an exception. +
The database enforces referential integrity, preventing the deletion of a referenced entity.

2. In *{product-name}*: +
Deleting an article from the article repository is allowed, even if it is still referenced elsewhere. +
The system does not track or enforce such references.
As a result:

* The article is removed from the repository.
* However, the order still retains its reference to the now-deleted article.
* If the order is subsequently saved, the article is reintroduced into the repository.

This behavior is fundamentally different from the strict relationship management seen in SQL databases.
Developers must be aware of these differences to avoid unintended side effects in their applications.
Loading

0 comments on commit a5d4b73

Please sign in to comment.