Skip to content

Commit 8fddd3a

Browse files
Auto fix problems with ids
1 parent 6b6feaa commit 8fddd3a

File tree

6 files changed

+241
-8
lines changed

6 files changed

+241
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
# 2.3.1
2+
3+
* Auto-Fix problems with adding ids to entities with existing data store.
4+
15
# 2.3.0
26

3-
* Add support for shuting down the storage during application shutdown
4-
* By default only enabled when Spring DevTools are active
7+
* Add support for shutting down the storage during application shutdown
8+
* By default, only enabled when Spring DevTools are active
59
* This should fix "StorageExceptionInitialization: Active storage for ... already exists" errors during DevTools restart
610
* Added [Jakarta Bean Validation Constraints](https://jakarta.ee/learn/docs/jakartaee-tutorial/current/beanvalidation/bean-validation/bean-validation.html#_using_jakarta_bean_validation_constraints) with Hibernate validator for entities.
711

docs/antora.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
name: ROOT
22
title: Spring-Data-Eclipse-Store
33
version: master
4-
display_version: '2.3.0'
4+
display_version: '2.3.1'
55
start_page: index.adoc
66
nav:
77
- modules/ROOT/nav.adoc
88
asciidoc:
99
attributes:
1010
product-name: 'Spring-Data-Eclipse-Store'
11-
display-version: '2.3.0'
12-
maven-version: '2.3.0'
11+
display-version: '2.3.1'
12+
maven-version: '2.3.1'
1313
page-editable: false
1414
page-out-of-support: false

spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/EclipseStoreStorage.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,14 @@ private <T, ID> void setIdManagerForEntityData(final Class<T> entityClass, final
205205
{
206206
final IdManager<T, ID> idManager = this.ensureIdManager(entityClass);
207207
final EntityData<T, Object> entityData = root.getCurrentRootData().getEntityData(entityClass);
208-
entityData.setIdGetter(idManager::getId);
208+
if(idManager.hasIdField())
209+
{
210+
entityData.setIdGetter(idManager::getId);
211+
}
212+
else
213+
{
214+
entityData.setIdGetter(null);
215+
}
209216
}
210217

211218
public synchronized <T> void registerEntity(

spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/root/EntityData.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,29 @@ public EntityData()
4848
this.entitiesById = new HashMap<>();
4949
}
5050

51+
/**
52+
* Accepts {@code null} if no id field is defined
53+
*
54+
* @param idGetter
55+
*/
5156
public void setIdGetter(final Function<T, ID> idGetter)
5257
{
5358
this.idGetter = idGetter;
59+
60+
this.ensureEntitiesAndEntitiesByIdAreTheSameSize();
61+
}
62+
63+
private void ensureEntitiesAndEntitiesByIdAreTheSameSize()
64+
{
65+
if(this.idGetter != null && this.entities.size() != this.entitiesById.size())
66+
{
67+
this.entitiesById.clear();
68+
this.entities.forEach(entity -> this.entitiesById.put(this.idGetter.apply(entity), entity));
69+
}
70+
if(this.idGetter == null)
71+
{
72+
this.entitiesById.clear();
73+
}
5474
}
5575

5676
public IdentitySet<T> getEntities()
@@ -83,7 +103,10 @@ public Collection<Object> ensureEntityAndReturnObjectsToStore(final T entityToSt
83103
if(!this.getEntities().contains(entityToStore))
84104
{
85105
this.entities.add(entityToStore);
86-
this.entitiesById.put(this.idGetter.apply(entityToStore), entityToStore);
106+
if(this.idGetter != null)
107+
{
108+
this.entitiesById.put(this.idGetter.apply(entityToStore), entityToStore);
109+
}
87110
return this.getObjectsToStore();
88111
}
89112
return List.of();
@@ -97,7 +120,10 @@ public Collection<Object> getObjectsToStore()
97120
public Collection<Object> removeEntityAndReturnObjectsToStore(final T entityToRemove)
98121
{
99122
this.entities.remove(entityToRemove);
100-
this.entitiesById.remove(this.idGetter.apply(entityToRemove));
123+
if(this.idGetter != null)
124+
{
125+
this.entitiesById.remove(this.idGetter.apply(entityToRemove));
126+
}
101127
return this.getObjectsToStore();
102128
}
103129

spring-data-eclipse-store/src/test/java/software/xdev/spring/data/eclipse/store/integration/isolated/tests/id/IdTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,33 @@ void replaceWithId(@Autowired final CustomerWithIdIntegerNoAutoGenerateRepositor
608608
);
609609
}
610610

611+
@Test
612+
void replaceWithIdAfterRestart(@Autowired final CustomerWithIdIntegerNoAutoGenerateRepository customerRepository)
613+
{
614+
final CustomerWithIdIntegerNoAutoGenerate existingCustomer =
615+
new CustomerWithIdIntegerNoAutoGenerate(1, TestData.FIRST_NAME, TestData.LAST_NAME);
616+
customerRepository.save(existingCustomer);
617+
618+
restartDatastore(this.configuration);
619+
620+
final CustomerWithIdIntegerNoAutoGenerate newCustomer =
621+
new CustomerWithIdIntegerNoAutoGenerate(1, TestData.FIRST_NAME_ALTERNATIVE,
622+
TestData.LAST_NAME_ALTERNATIVE);
623+
customerRepository.save(newCustomer);
624+
625+
TestUtil.doBeforeAndAfterRestartOfDatastore(
626+
this.configuration,
627+
() -> {
628+
final List<CustomerWithIdIntegerNoAutoGenerate> loadedCustomer =
629+
TestUtil.iterableToList(customerRepository.findAll());
630+
631+
Assertions.assertEquals(1, loadedCustomer.size());
632+
Assertions.assertEquals(TestData.FIRST_NAME_ALTERNATIVE, loadedCustomer.get(0).getFirstName());
633+
Assertions.assertEquals(TestData.LAST_NAME_ALTERNATIVE, loadedCustomer.get(0).getLastName());
634+
}
635+
);
636+
}
637+
611638
@Test
612639
void replaceWithAutoId(@Autowired final CustomerWithIdIntegerRepository customerRepository)
613640
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright © 2024 XDEV Software (https://xdev.software)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package software.xdev.spring.data.eclipse.store.repository.root;
17+
18+
import java.util.function.Function;
19+
20+
import org.junit.jupiter.api.Assertions;
21+
import org.junit.jupiter.api.Test;
22+
23+
import software.xdev.spring.data.eclipse.store.helper.TestData;
24+
25+
26+
class EntityDataTest
27+
{
28+
record Person(String id, String name)
29+
{
30+
}
31+
32+
33+
private final Function<Person, String> idGetter = person -> person.id;
34+
private final Function<Person, String> idNullGetter = person -> null;
35+
36+
@Test
37+
void idGetterIsNotSet()
38+
{
39+
final EntityData<Person, String> testData = new EntityData<>();
40+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
41+
Assertions.assertTrue(testData.getEntitiesById().isEmpty());
42+
Assertions.assertEquals(1, testData.getEntities().size());
43+
}
44+
45+
@Test
46+
void idGetterSetAndNothingAdded()
47+
{
48+
final EntityData<Person, String> testData = new EntityData<>();
49+
testData.setIdGetter(this.idGetter);
50+
Assertions.assertTrue(testData.getEntitiesById().isEmpty());
51+
Assertions.assertTrue(testData.getEntities().isEmpty());
52+
}
53+
54+
@Test
55+
void idGetterNotSetSetAndNothingAdded()
56+
{
57+
final EntityData<Person, String> testData = new EntityData<>();
58+
Assertions.assertTrue(testData.getEntitiesById().isEmpty());
59+
Assertions.assertTrue(testData.getEntities().isEmpty());
60+
}
61+
62+
@Test
63+
void idGetterSet()
64+
{
65+
final EntityData<Person, String> testData = new EntityData<>();
66+
testData.setIdGetter(this.idGetter);
67+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
68+
Assertions.assertEquals(1, testData.getEntitiesById().size());
69+
Assertions.assertEquals(1, testData.getEntities().size());
70+
}
71+
72+
@Test
73+
void idGetterSetToNull()
74+
{
75+
final EntityData<Person, String> testData = new EntityData<>();
76+
testData.setIdGetter(this.idNullGetter);
77+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
78+
Assertions.assertEquals(1, testData.getEntitiesById().size());
79+
Assertions.assertEquals(1, testData.getEntities().size());
80+
}
81+
82+
@Test
83+
void idGetterSetToNullWith2Entities()
84+
{
85+
final EntityData<Person, String> testData = new EntityData<>();
86+
testData.setIdGetter(this.idNullGetter);
87+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
88+
testData.ensureEntityAndReturnObjectsToStore(new Person("2", TestData.FIRST_NAME_ALTERNATIVE));
89+
Assertions.assertEquals(1, testData.getEntitiesById().size());
90+
Assertions.assertEquals(2, testData.getEntities().size());
91+
}
92+
93+
@Test
94+
void idGetterSetWith2Entities()
95+
{
96+
final EntityData<Person, String> testData = new EntityData<>();
97+
testData.setIdGetter(this.idGetter);
98+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
99+
testData.ensureEntityAndReturnObjectsToStore(new Person("2", TestData.FIRST_NAME_ALTERNATIVE));
100+
Assertions.assertEquals(2, testData.getEntitiesById().size());
101+
Assertions.assertEquals(2, testData.getEntities().size());
102+
}
103+
104+
@Test
105+
void idGetterFirstNullThenReturningIdSameObject()
106+
{
107+
final EntityData<Person, String> testData = new EntityData<>();
108+
testData.setIdGetter(null);
109+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
110+
testData.ensureEntityAndReturnObjectsToStore(new Person("2", TestData.FIRST_NAME_ALTERNATIVE));
111+
Assertions.assertTrue(testData.getEntitiesById().isEmpty());
112+
Assertions.assertEquals(2, testData.getEntities().size());
113+
114+
testData.setIdGetter(this.idGetter);
115+
final Person foundPerson = testData.getEntities().stream().findFirst().get();
116+
testData.ensureEntityAndReturnObjectsToStore(foundPerson);
117+
Assertions.assertEquals(2, testData.getEntitiesById().size());
118+
Assertions.assertEquals(2, testData.getEntities().size());
119+
}
120+
121+
@Test
122+
void idGetterFirstReturnNullThenReturningIdSameObject()
123+
{
124+
final EntityData<Person, String> testData = new EntityData<>();
125+
testData.setIdGetter(this.idNullGetter);
126+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
127+
testData.ensureEntityAndReturnObjectsToStore(new Person("2", TestData.FIRST_NAME_ALTERNATIVE));
128+
Assertions.assertEquals(1, testData.getEntitiesById().size());
129+
Assertions.assertEquals(2, testData.getEntities().size());
130+
131+
testData.setIdGetter(this.idGetter);
132+
final Person foundPerson = testData.getEntities().stream().findFirst().get();
133+
testData.ensureEntityAndReturnObjectsToStore(foundPerson);
134+
Assertions.assertEquals(2, testData.getEntitiesById().size());
135+
Assertions.assertEquals(2, testData.getEntities().size());
136+
}
137+
138+
@Test
139+
void idGetterFirstNullThenReturningIdDifferentObject()
140+
{
141+
final EntityData<Person, String> testData = new EntityData<>();
142+
testData.setIdGetter(null);
143+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
144+
testData.ensureEntityAndReturnObjectsToStore(new Person("2", TestData.FIRST_NAME_ALTERNATIVE));
145+
Assertions.assertTrue(testData.getEntitiesById().isEmpty());
146+
Assertions.assertEquals(2, testData.getEntities().size());
147+
148+
testData.setIdGetter(this.idGetter);
149+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
150+
Assertions.assertEquals(2, testData.getEntitiesById().size());
151+
Assertions.assertEquals(3, testData.getEntities().size());
152+
}
153+
154+
@Test
155+
void idGetterFirstReturnNullThenReturningIdDifferentObject()
156+
{
157+
final EntityData<Person, String> testData = new EntityData<>();
158+
testData.setIdGetter(this.idNullGetter);
159+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
160+
testData.ensureEntityAndReturnObjectsToStore(new Person("2", TestData.FIRST_NAME_ALTERNATIVE));
161+
Assertions.assertEquals(1, testData.getEntitiesById().size());
162+
Assertions.assertEquals(2, testData.getEntities().size());
163+
164+
testData.setIdGetter(this.idGetter);
165+
testData.ensureEntityAndReturnObjectsToStore(new Person("1", TestData.FIRST_NAME));
166+
Assertions.assertEquals(2, testData.getEntitiesById().size());
167+
Assertions.assertEquals(3, testData.getEntities().size());
168+
}
169+
}

0 commit comments

Comments
 (0)