Skip to content

Lazy repositories #200

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

Merged
merged 20 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
69f16ef
LazyRepositories: first test with simple lazy wrapper
JohannesRabauer Dec 3, 2024
00d4907
LazyRepositories: Added basic LazySimpleEclipseStoreRepository
JohannesRabauer Dec 3, 2024
10c285c
LazyRepositories: Implemented StorageCommunicator
JohannesRabauer Dec 3, 2024
a46bdf1
Implemented LazyRepositories, new EntityData and refactoring
JohannesRabauer Dec 6, 2024
cd26674
Implemented LazyEntitiyData as Lazy
JohannesRabauer Dec 6, 2024
1d2bd3a
Fix - Nonlazy functionality
JohannesRabauer Dec 9, 2024
aff511d
Simple Lazy Tests working
JohannesRabauer Dec 9, 2024
f4b4e4e
Minor fixes and refactoring
JohannesRabauer Dec 9, 2024
6930b5a
Isolated real life example tests
JohannesRabauer Dec 9, 2024
e3a29c2
Delete RealLifeTests.java
JohannesRabauer Dec 9, 2024
474f339
Added Lazy Tests to real life example tests
JohannesRabauer Dec 9, 2024
1846bc5
Fixed some lazy repo problems
JohannesRabauer Dec 9, 2024
dea9f9e
Moved Simple Tests to isolated tests
JohannesRabauer Dec 9, 2024
c597730
Simple Tests now work with LazyRepositories
JohannesRabauer Dec 9, 2024
8697304
Lazy References in Repositories are now real ES Lazies
JohannesRabauer Dec 9, 2024
2c36144
Expanded Test to look for lazy implementation
JohannesRabauer Dec 9, 2024
2eedf70
Add LazyRepo demo
JohannesRabauer Dec 9, 2024
c94f087
Added lazy documentation
JohannesRabauer Dec 9, 2024
7c7fbe4
Checkstyle fixes
JohannesRabauer Dec 9, 2024
911c2fa
Stopped executing pmd cpd check because it is not working to exclude …
JohannesRabauer Dec 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/check-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,6 @@ jobs:
- name: Run PMD
run: ./mvnw -B test pmd:aggregate-pmd-no-fork pmd:check -P pmd -DskipTests -T2C

- name: Run CPD (Copy Paste Detector)
run: ./mvnw -B pmd:aggregate-cpd pmd:cpd-check -P pmd -DskipTests -T2C

- name: Upload report
if: always()
uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ spring-data-eclipse-store-demo/storage
spring-data-eclipse-store-demo/storage-person
spring-data-eclipse-store-demo/storage-invoice
spring-data-eclipse-store-demo/storage-complex
spring-data-eclipse-store-demo/storage-lazy
spring-data-eclipse-store-jpa/storage-eclipsestore
spring-data-eclipse-store-jpa/storage-h2.mv.db
spring-data-eclipse-store-jpa/storage-h2.trace.db
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

* Updated org.springframework.boot.version to v3.4.0
* Updated EclipseStore to v2.0.0
* Implemented Lazy Repositories with ``LazyEclipseStoreRepository``

# 2.3.1

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ the [demos](./spring-data-eclipse-store-demo):

* [Simple demo](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/simple)
* [Complex demo](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)
* [Lazy demo](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/lazy)
* [Demo with coexisting JPA](https://github.com/xdev-software/spring-data-eclipse-store/tree/develop/spring-data-eclipse-store-jpa/src/main/java/software/xdev/spring/data/eclipse/store/jpa)
* [Dual storage demo](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/dual/storage)

Expand Down
30 changes: 29 additions & 1 deletion docs/modules/ROOT/pages/features/lazies.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,38 @@ public class Owner extends Person
{
private String address;

private Lazy<List<Pet>> pets = SpringDataEclipseStoreLazy.build(new ArrayList<>());
private final Lazy<List<Pet>> pets = SpringDataEclipseStoreLazy.build(new ArrayList<>());
//...
----

== Repositories

Entities in a repository are by default **not lazy**.
But we made it as easy as possible for you to make these entities lazy: Instead of extending the ``EclipseStoreRepository`` (or any similar class from the ``software.xdev.spring.data.eclipse.store.repository.interfaces``-Package), you simply extend the ``LazyEclipseStoreRepository``.

=== 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/lazy/CustomerRepository.java[Example from lazy demo]

[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/simple/CustomerRepository.java[Before (not lazy)]"]
----
public interface CustomerRepository extends CrudRepository<Customer, String>
{
}
----

[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/lazy/CustomerRepository.java[After (lazy)]"]
----
public interface CustomerRepository extends LazyEclipseStoreCrudRepository<Customer, String>
{
}
----

Every instance of the ``Customer``-Entities are now wrapped in a https://docs.eclipsestore.io/manual/storage/loading-data/lazy-loading/index.html[``Lazy``-Reference].
That means that these objects are **only loaded from the storage, if they are needed** e.g. when ``findAll`` is called.

The method **``findById`` only loads the entities with the corresponding IDs**, because a separate list with all ids is stored.
But if any method like **``findByName`` or ``findByChild`` is used, all objects are loaded** from the storage.
This is currently the only way to get the actual values of the entities.

== Internals

SpringDataEclipseStoreLazies work as a proxy for the EclipseStore-Lazies.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package software.xdev.spring.data.eclipse.store.demo.lazy;

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;

import org.springframework.data.annotation.Id;


public class Customer
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private String id;

private final String firstName;
private final String lastName;

public Customer(final String firstName, final String lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}

@Override
public String toString()
{
return String.format(
"Customer[id=%s, firstName='%s', lastName='%s']",
this.id, this.firstName, this.lastName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package software.xdev.spring.data.eclipse.store.demo.lazy;

import software.xdev.spring.data.eclipse.store.repository.interfaces.lazy.LazyEclipseStoreCrudRepository;


public interface CustomerRepository extends LazyEclipseStoreCrudRepository<Customer, String>
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package software.xdev.spring.data.eclipse.store.demo.lazy;

import java.nio.file.Path;

import org.eclipse.serializer.reflect.ClassLoaderProvider;
import org.eclipse.store.integrations.spring.boot.types.configuration.EclipseStoreProperties;
import org.eclipse.store.integrations.spring.boot.types.factories.EmbeddedStorageFoundationFactory;
import org.eclipse.store.storage.embedded.types.EmbeddedStorage;
import org.eclipse.store.storage.embedded.types.EmbeddedStorageFoundation;
import org.eclipse.store.storage.types.Storage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import software.xdev.spring.data.eclipse.store.demo.dual.storage.person.PersistencePersonConfiguration;
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreClientConfiguration;
import software.xdev.spring.data.eclipse.store.repository.config.EnableEclipseStoreRepositories;


@Configuration
@EnableEclipseStoreRepositories
public class LazyConfiguration extends EclipseStoreClientConfiguration
{

public static final String STORAGE_PATH = "storage-lazy";

@Autowired
public LazyConfiguration(
final EclipseStoreProperties defaultEclipseStoreProperties,
final EmbeddedStorageFoundationFactory defaultEclipseStoreProvider,
final ClassLoaderProvider classLoaderProvider
)
{
super(defaultEclipseStoreProperties, defaultEclipseStoreProvider, classLoaderProvider);
}
/**
* This is one option how to configure the {@link EmbeddedStorageFoundation}.
* <p>
* We create a completely new foundation. That means that all configuration (e.g. properties) are not used here.
* With this method you have complete control over the configuration.
* </p>
* Another example: {@link PersistencePersonConfiguration#createEmbeddedStorageFoundation()}
*/
@Override
public EmbeddedStorageFoundation<?> createEmbeddedStorageFoundation()
{
final EmbeddedStorageFoundation<?> storageFoundation =
EmbeddedStorage.Foundation(Storage.Configuration(Storage.FileProvider(Path.of(STORAGE_PATH))));
// This is only needed, if a different ClassLoader is used (e.g. when using spring-dev-tools)
storageFoundation.getConnectionFoundation().setClassLoaderProvider(this.getClassLoaderProvider());
return storageFoundation;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package software.xdev.spring.data.eclipse.store.demo.lazy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class LazyDemoApplication implements CommandLineRunner
{
private static final Logger LOG = LoggerFactory.getLogger(LazyDemoApplication.class);
private final CustomerRepository customerRepository;
private final PetRepository petRepository;

public LazyDemoApplication(
final CustomerRepository customerRepository,
final PetRepository petRepository
)
{
this.customerRepository = customerRepository;
this.petRepository = petRepository;
}

public static void main(final String[] args)
{
SpringApplication.run(LazyDemoApplication.class, args);
}

@Override
public void run(final String... args)
{
this.customerRepository.deleteAll();

// save a couple of customers
this.customerRepository.save(new Customer("Stevie", "Nicks"));
this.customerRepository.save(new Customer("Mick", "Fleetwood"));

// fetch all customers
LOG.info("Customers found with findAll():");
this.customerRepository.findAll().forEach(c -> LOG.info(c.toString()));

// save a pet
this.petRepository.save(new Pet("1", "Peter", 2));

// fetch all pets
LOG.info("Pets found with findAll():");
this.petRepository.findAll().forEach(p -> LOG.info(p.toString()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package software.xdev.spring.data.eclipse.store.demo.lazy;

import org.springframework.data.annotation.Id;


public class Pet
{
@Id
private String id;

private String name;
private Integer age;

public Pet()
{
}

public Pet(final String id, final String name, final Integer age)
{
this.id = id;
this.name = name;
this.age = age;
}

@Override
public String toString()
{
return String.format(
"Pet[id=%s, name='%s', age='%s']",
this.id, this.name, this.age);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package software.xdev.spring.data.eclipse.store.demo.lazy;

import software.xdev.spring.data.eclipse.store.repository.interfaces.lazy.LazyEclipseStoreCrudRepository;


public interface PetRepository extends LazyEclipseStoreCrudRepository<Pet, String>
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package software.xdev.spring.data.eclipse.store.demo.lazy.complex;

import java.io.File;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import software.xdev.spring.data.eclipse.store.demo.TestUtil;
import software.xdev.spring.data.eclipse.store.demo.lazy.LazyConfiguration;
import software.xdev.spring.data.eclipse.store.demo.lazy.LazyDemoApplication;
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreClientConfiguration;


@SpringBootTest(classes = LazyDemoApplication.class)
class LazyDemoApplicationTest
{
private final EclipseStoreClientConfiguration configuration;

@Autowired
public LazyDemoApplicationTest(final LazyConfiguration configuration)
{
this.configuration = configuration;
}

@BeforeAll
static void clearPreviousData()
{
TestUtil.deleteDirectory(new File("./" + LazyConfiguration.STORAGE_PATH));
}

@Test
void checkPossibilityToSimplyStartAndRestartApplication()
{
this.configuration.getStorageInstance().stop();
LazyDemoApplication.main(new String[]{});
}
}
2 changes: 2 additions & 0 deletions spring-data-eclipse-store/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>${javaVersion}</source>
<target>${javaVersion}</target>
<release>${maven.compiler.release}</release>
<compilerArgs>
<arg>-proc:none</arg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,4 @@
public interface EntityListProvider
{
<T, ID> EntityProvider<T, ID> getEntityProvider(final Class<T> clazz);

<T> long getEntityCount(final Class<T> clazz);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import software.xdev.spring.data.eclipse.store.repository.root.EntityData;
import software.xdev.spring.data.eclipse.store.repository.root.v2_4.EntityData;


@SuppressWarnings("java:S119")
Expand All @@ -38,7 +38,7 @@ public void addEntityData(final EntityData<? extends T, ID> entityData)

public Stream<? extends T> stream()
{
return this.entityDataList.stream().map(EntityData::getEntities).flatMap(Set::stream);
return this.entityDataList.stream().flatMap(EntityData::getEntitiesAsStream);
}

public Collection<T> toCollection()
Expand All @@ -56,12 +56,13 @@ public long size()
return this.stream().count();
}

@SuppressWarnings("unchecked")
public Optional<T> findAnyEntityWithId(final ID id)
{
return (Optional<T>)this.entityDataList
.stream()
.map(entityData -> entityData.getEntitiesById().get(id))
.filter(e -> e != null)
.map(entityData -> entityData.getEntityById(id))
.filter(Objects::nonNull)
.findAny();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
import software.xdev.micromigration.version.MigrationVersion;
import software.xdev.spring.data.eclipse.store.repository.root.VersionedRoot;
import software.xdev.spring.data.eclipse.store.repository.root.update.scripts.v2_0_0_InitializeVersioning;
import software.xdev.spring.data.eclipse.store.repository.root.update.scripts.v2_4_0_InitializeLazy;


public final class EclipseStoreMigrator
{
public static final VersionAgnosticMigrationScript<?, ?>[] SCRIPTS =
new VersionAgnosticMigrationScript[]{
new v2_0_0_InitializeVersioning()
new v2_0_0_InitializeVersioning(),
new v2_4_0_InitializeLazy()
};

private EclipseStoreMigrator()
Expand Down
Loading
Loading