Skip to content

Commit 3edab69

Browse files
committed
Fixed saving collections in persisted values #21
1 parent 6c39b1d commit 3edab69

File tree

7 files changed

+190
-76
lines changed

7 files changed

+190
-76
lines changed

core/src/main/java/net/lecousin/reactive/data/relational/enhance/EntityState.java

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,6 @@
1313
*/
1414
package net.lecousin.reactive.data.relational.enhance;
1515

16-
import java.lang.reflect.Array;
17-
import java.lang.reflect.Field;
18-
import java.util.Collection;
19-
import java.util.HashMap;
20-
import java.util.LinkedList;
21-
import java.util.List;
22-
import java.util.Map;
23-
import java.util.function.Function;
24-
import java.util.function.Supplier;
25-
26-
import org.apache.commons.lang3.mutable.MutableObject;
27-
import org.springframework.core.CollectionFactory;
28-
import org.springframework.data.mapping.MappingException;
29-
import org.springframework.lang.NonNull;
30-
import org.springframework.lang.Nullable;
31-
3216
import net.lecousin.reactive.data.relational.LcReactiveDataRelationalClient;
3317
import net.lecousin.reactive.data.relational.model.ModelAccessException;
3418
import net.lecousin.reactive.data.relational.model.ModelUtils;
@@ -38,14 +22,28 @@
3822
import net.lecousin.reactive.data.relational.model.metadata.PropertyStaticMetadata;
3923
import net.lecousin.reactive.data.relational.query.SelectQuery;
4024
import net.lecousin.reactive.data.relational.query.criteria.Criteria;
25+
import org.apache.commons.lang3.mutable.MutableObject;
26+
import org.springframework.core.CollectionFactory;
27+
import org.springframework.data.mapping.MappingException;
28+
import org.springframework.lang.NonNull;
29+
import org.springframework.lang.Nullable;
4130
import reactor.core.CorePublisher;
4231
import reactor.core.publisher.Flux;
4332
import reactor.core.publisher.Mono;
4433

34+
import java.lang.reflect.Array;
35+
import java.lang.reflect.Field;
36+
import java.util.Collection;
37+
import java.util.HashMap;
38+
import java.util.Map;
39+
import java.util.function.Function;
40+
import java.util.function.Supplier;
41+
4542
/**
4643
* Internal state of an entity, allowing to implement features such as lazy loading, updated attributes detection...
4744
*
4845
* @author Guillaume Le Cousin
46+
* @author Sebastian Nawrocki
4947
*
5048
*/
5149
public class EntityState {
@@ -154,9 +152,10 @@ private void updatePersistedValues(Object entity) {
154152

155153
private void savePersistedValue(Field field, Object value) {
156154
if (value != null && ModelUtils.isCollection(field)) {
157-
List<Object> list = new LinkedList<>();
158-
list.addAll(ModelUtils.getAsCollection(value));
159-
persistedValues.put(field.getName(), list);
155+
Collection<Object> valueAsCollection = ModelUtils.getAsCollection(value);
156+
Collection<Object> collection = CollectionFactory.createApproximateCollection(valueAsCollection, 10);
157+
collection.addAll(valueAsCollection);
158+
persistedValues.put(field.getName(), collection);
160159
} else {
161160
persistedValues.put(field.getName(), value);
162161
}

core/src/main/java/net/lecousin/reactive/data/relational/model/ModelUtils.java

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@
1313
*/
1414
package net.lecousin.reactive.data.relational.model;
1515

16+
import net.lecousin.reactive.data.relational.annotations.CompositeId;
17+
import net.lecousin.reactive.data.relational.enhance.EntityState;
18+
import net.lecousin.reactive.data.relational.model.metadata.EntityMetadata;
19+
import net.lecousin.reactive.data.relational.model.metadata.EntityStaticMetadata;
20+
import net.lecousin.reactive.data.relational.model.metadata.PropertyMetadata;
21+
import net.lecousin.reactive.data.relational.model.metadata.PropertyStaticMetadata;
22+
import org.apache.commons.lang3.ArrayUtils;
23+
import org.springframework.core.CollectionFactory;
24+
import org.springframework.data.mapping.MappingException;
25+
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
26+
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
27+
import org.springframework.lang.NonNull;
28+
import org.springframework.lang.Nullable;
29+
1630
import java.lang.reflect.Array;
1731
import java.lang.reflect.Field;
1832
import java.lang.reflect.ParameterizedType;
@@ -25,21 +39,6 @@
2539
import java.util.List;
2640
import java.util.function.Function;
2741

28-
import org.apache.commons.lang3.ArrayUtils;
29-
import org.springframework.core.CollectionFactory;
30-
import org.springframework.data.mapping.MappingException;
31-
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
32-
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
33-
import org.springframework.lang.NonNull;
34-
import org.springframework.lang.Nullable;
35-
36-
import net.lecousin.reactive.data.relational.annotations.CompositeId;
37-
import net.lecousin.reactive.data.relational.enhance.EntityState;
38-
import net.lecousin.reactive.data.relational.model.metadata.EntityMetadata;
39-
import net.lecousin.reactive.data.relational.model.metadata.EntityStaticMetadata;
40-
import net.lecousin.reactive.data.relational.model.metadata.PropertyMetadata;
41-
import net.lecousin.reactive.data.relational.model.metadata.PropertyStaticMetadata;
42-
4342
/**
4443
* Utility methods.
4544
*
@@ -120,9 +119,7 @@ public static boolean isCollection(Field field) {
120119
public static boolean isCollectionType(Class<?> type) {
121120
if (type.isArray())
122121
return !char[].class.equals(type);
123-
if (Collection.class.isAssignableFrom(type))
124-
return true;
125-
return false;
122+
return Collection.class.isAssignableFrom(type);
126123
}
127124

128125
/** Return the given object as a collection.
@@ -164,11 +161,9 @@ public static Class<?> getCollectionType(Field field) {
164161
* @return type of elements
165162
*/
166163
public static Class<?> getRequiredCollectionType(Field field) {
167-
if (field.getType().isArray())
168-
return field.getType().getComponentType();
169-
Type genType = field.getGenericType();
170-
if (genType instanceof ParameterizedType)
171-
return (Class<?>) ((ParameterizedType)genType).getActualTypeArguments()[0];
164+
Class<?> collectionType = getCollectionType(field);
165+
if (collectionType != null)
166+
return collectionType;
172167
throw new MappingException("Field is not a collection: " + field.getDeclaringClass().getName() + "." + field.getName());
173168
}
174169

core/src/test/java/net/lecousin/reactive/data/relational/test/AbstractLcReactiveDataRelationalTest.java

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package net.lecousin.reactive.data.relational.test;
22

3-
import java.lang.reflect.Method;
4-
import java.util.ArrayList;
5-
import java.util.Collection;
6-
import java.util.Collections;
7-
import java.util.Iterator;
8-
import java.util.LinkedList;
9-
import java.util.List;
10-
import java.util.Objects;
11-
import java.util.function.Function;
12-
13-
import javax.annotation.PostConstruct;
14-
3+
import net.lecousin.reactive.data.relational.LcReactiveDataRelationalClient;
4+
import net.lecousin.reactive.data.relational.model.metadata.EntityStaticMetadata;
5+
import net.lecousin.reactive.data.relational.query.SelectQuery;
6+
import net.lecousin.reactive.data.relational.repository.LcR2dbcEntityTemplate;
7+
import net.lecousin.reactive.data.relational.schema.RelationalDatabaseSchema;
8+
import net.lecousin.reactive.data.relational.test.arraycolumns.EntityWithArrays;
9+
import net.lecousin.reactive.data.relational.test.arraycolumns.UpdateableCollectionProperties;
10+
import net.lecousin.reactive.data.relational.test.simplemodel.DateTypesWithTimeZone;
1511
import org.junit.jupiter.api.AfterEach;
1612
import org.junit.jupiter.api.Assertions;
1713
import org.junit.jupiter.api.BeforeEach;
@@ -25,13 +21,17 @@
2521
import org.springframework.test.annotation.DirtiesContext;
2622
import org.springframework.test.annotation.DirtiesContext.ClassMode;
2723

28-
import net.lecousin.reactive.data.relational.LcReactiveDataRelationalClient;
29-
import net.lecousin.reactive.data.relational.model.metadata.EntityStaticMetadata;
30-
import net.lecousin.reactive.data.relational.query.SelectQuery;
31-
import net.lecousin.reactive.data.relational.repository.LcR2dbcEntityTemplate;
32-
import net.lecousin.reactive.data.relational.schema.RelationalDatabaseSchema;
33-
import net.lecousin.reactive.data.relational.test.arraycolumns.EntityWithArrays;
34-
import net.lecousin.reactive.data.relational.test.simplemodel.DateTypesWithTimeZone;
24+
import javax.annotation.PostConstruct;
25+
import java.lang.reflect.Method;
26+
import java.util.ArrayList;
27+
import java.util.Collection;
28+
import java.util.Collections;
29+
import java.util.Iterator;
30+
import java.util.LinkedList;
31+
import java.util.List;
32+
import java.util.Objects;
33+
import java.util.Set;
34+
import java.util.function.Function;
3535

3636
@DataR2dbcTest
3737
@EnableAutoConfiguration
@@ -77,9 +77,9 @@ public void initDatabase() {
7777
protected Collection<Class<?>> getAllCompatibleEntities() {
7878
Collection<Class<?>> entities = new LinkedList<>(EntityStaticMetadata.getClasses());
7979
if (!lcClient.getSchemaDialect().isTimeZoneSupported())
80-
entities.remove(DateTypesWithTimeZone.class);
80+
entities.removeAll(Set.of(DateTypesWithTimeZone.class));
8181
if (!lcClient.getSchemaDialect().isArrayColumnSupported())
82-
entities.remove(EntityWithArrays.class);
82+
entities.removeAll(Set.of(EntityWithArrays.class, UpdateableCollectionProperties.class));
8383
return entities;
8484
}
8585

core/src/test/java/net/lecousin/reactive/data/relational/test/arraycolumns/AbstractTestArrayColumns.java

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package net.lecousin.reactive.data.relational.test.arraycolumns;
22

3-
import java.util.Arrays;
4-
import java.util.Collection;
5-
import java.util.List;
6-
3+
import net.lecousin.reactive.data.relational.query.SelectQuery;
4+
import net.lecousin.reactive.data.relational.query.criteria.Criteria;
5+
import net.lecousin.reactive.data.relational.repository.LcR2dbcRepositoryFactoryBean;
6+
import net.lecousin.reactive.data.relational.test.AbstractLcReactiveDataRelationalTest;
77
import org.junit.jupiter.api.Assertions;
88
import org.junit.jupiter.api.Test;
99
import org.springframework.beans.factory.annotation.Autowired;
1010
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories;
1111

12-
import net.lecousin.reactive.data.relational.query.SelectQuery;
13-
import net.lecousin.reactive.data.relational.query.criteria.Criteria;
14-
import net.lecousin.reactive.data.relational.repository.LcR2dbcRepositoryFactoryBean;
15-
import net.lecousin.reactive.data.relational.test.AbstractLcReactiveDataRelationalTest;
12+
import java.util.Arrays;
13+
import java.util.Collection;
14+
import java.util.List;
15+
import java.util.Set;
1616

1717
@EnableR2dbcRepositories(repositoryFactoryBeanClass = LcR2dbcRepositoryFactoryBean.class)
1818
public abstract class AbstractTestArrayColumns extends AbstractLcReactiveDataRelationalTest {
@@ -22,7 +22,7 @@ public abstract class AbstractTestArrayColumns extends AbstractLcReactiveDataRel
2222

2323
@Override
2424
protected Collection<Class<?>> usedEntities() {
25-
return Arrays.asList(EntityWithArrays.class);
25+
return Arrays.asList(EntityWithArrays.class, UpdateableCollectionProperties.class);
2626
}
2727

2828
@Test
@@ -33,6 +33,7 @@ public void testEmptyArrays() {
3333
entity = repo1.findAll().blockFirst();
3434
Assertions.assertTrue(entity.getIntegers() == null || entity.getIntegers().length == 0);
3535
Assertions.assertTrue(entity.getPrimitiveIntegers() == null || entity.getPrimitiveIntegers().length == 0);
36+
Assertions.assertTrue(entity.getIntegerList() == null || entity.getIntegerList().size() == 0);
3637
}
3738

3839
@Test
@@ -58,6 +59,7 @@ public void testArraysWithOneElement() {
5859
entity.setDoubleList(Arrays.asList(4.5d));
5960
entity.setStrings(new String[] { "test1" });
6061
entity.setStringList(Arrays.asList("test2"));
62+
entity.setStringSet(Set.of("test3"));
6163
repo1.save(entity).block();
6264

6365
entity = repo1.findAll().blockFirst();
@@ -141,6 +143,10 @@ public void testArraysWithOneElement() {
141143
Assertions.assertNotNull(entity.getStringList());
142144
Assertions.assertEquals(1, entity.getStringList().size());
143145
Assertions.assertEquals("test2", entity.getStringList().get(0));
146+
147+
Assertions.assertNotNull(entity.getStringSet());
148+
Assertions.assertEquals(1, entity.getStringSet().size());
149+
Assertions.assertEquals("test3", entity.getStringSet().iterator().next());
144150

145151
// update an element in the array
146152
entity.getIntegers()[0] = 12345;
@@ -197,4 +203,39 @@ public void testSearchEntityHavingAnArrayContaining() {
197203
.collectList().block();
198204
Assertions.assertEquals(2, list.size());
199205
}
206+
207+
@Test
208+
public void testArraysWithUpdateableCollectionProperties() {
209+
UpdateableCollectionProperties entity = new UpdateableCollectionProperties();
210+
entity.setStrings1(List.of("1.1"));
211+
entity.setStrings2(Set.of("2.1"));
212+
entity.setStrings3(List.of("3.1"));
213+
entity.setStrings4(Set.of("4.1"));
214+
215+
entity = lcClient.save(entity).block();
216+
Assertions.assertEquals(List.of("1.1"), entity.getStrings1());
217+
Assertions.assertEquals(Set.of("2.1"), entity.getStrings2());
218+
Assertions.assertEquals(List.of("3.1"), entity.getStrings3());
219+
Assertions.assertEquals(Set.of("4.1"), entity.getStrings4());
220+
long id = entity.getId();
221+
222+
entity.setStrings1(List.of("1.2"));
223+
entity.setStrings2(Set.of("2.2"));
224+
entity.setStrings3(List.of("3.2"));
225+
entity.setStrings4(Set.of("4.2"));
226+
227+
entity = lcClient.save(entity).block();
228+
Assertions.assertEquals(id, entity.getId());
229+
Assertions.assertEquals(List.of("1.2"), entity.getStrings1());
230+
Assertions.assertEquals(Set.of("2.2"), entity.getStrings2());
231+
Assertions.assertEquals(List.of("3.1"), entity.getStrings3());
232+
Assertions.assertEquals(Set.of("4.1"), entity.getStrings4());
233+
234+
entity = SelectQuery.from(UpdateableCollectionProperties.class, "entity").execute(lcClient).blockFirst();
235+
Assertions.assertEquals(id, entity.getId());
236+
Assertions.assertEquals(List.of("1.2"), entity.getStrings1());
237+
Assertions.assertEquals(Set.of("2.2"), entity.getStrings2());
238+
Assertions.assertEquals(List.of("3.1"), entity.getStrings3());
239+
Assertions.assertEquals(Set.of("4.1"), entity.getStrings4());
240+
}
200241
}

core/src/test/java/net/lecousin/reactive/data/relational/test/arraycolumns/EntityWithArrays.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package net.lecousin.reactive.data.relational.test.arraycolumns;
22

3-
import java.util.List;
4-
3+
import net.lecousin.reactive.data.relational.annotations.GeneratedValue;
54
import org.springframework.data.annotation.Id;
65
import org.springframework.data.relational.core.mapping.Column;
76
import org.springframework.data.relational.core.mapping.Table;
87

9-
import net.lecousin.reactive.data.relational.annotations.GeneratedValue;
8+
import java.util.List;
9+
import java.util.Set;
1010

1111
@Table
1212
public class EntityWithArrays {
@@ -74,6 +74,9 @@ public class EntityWithArrays {
7474
@Column
7575
private List<String> stringList;
7676

77+
@Column
78+
private Set<String> stringSet;
79+
7780
public Long getId() {
7881
return id;
7982
}
@@ -241,5 +244,12 @@ public List<String> getStringList() {
241244
public void setStringList(List<String> stringList) {
242245
this.stringList = stringList;
243246
}
244-
247+
248+
public Set<String> getStringSet() {
249+
return stringSet;
250+
}
251+
252+
public void setStringSet(Set<String> stringSet) {
253+
this.stringSet = stringSet;
254+
}
245255
}

0 commit comments

Comments
 (0)