Browse Source

DATAJDBC-183 - Using dedicated class for handling map entries.

Instead of using Map.Entry we now use a dedicated class to hold key and value of a map entry.
This avoids side effects from the implementation of Map.Entry.

Replaced call to saveReferencedEntities with insertReferencedEntities which is simpler but equivalent since referenced entities always get only inserted, never updated.

Removed superfluous methods resulting from that change.
pull/53/merge
Jens Schauder 8 years ago committed by Greg Turnquist
parent
commit
cb302e90a6
No known key found for this signature in database
GPG Key ID: CB2FA4D512B5C413
  1. 100
      src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriter.java
  2. 39
      src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java

100
src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriter.java

@ -15,7 +15,14 @@ @@ -15,7 +15,14 @@
*/
package org.springframework.data.jdbc.core.conversion;
import lombok.RequiredArgsConstructor;
import lombok.Data;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
import org.springframework.data.jdbc.core.conversion.DbAction.Update;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
@ -27,13 +34,6 @@ import org.springframework.data.mapping.PersistentPropertyAccessor; @@ -27,13 +34,6 @@ import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.util.StreamUtils;
import org.springframework.util.ClassUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Stream;
/**
* Converts an entity that is about to be saved into {@link DbAction}s inside a {@link AggregateChange} that need to be
* executed against the database to recreate the appropriate state in the database.
@ -62,8 +62,15 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport { @@ -62,8 +62,15 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
Insert<Object> insert = DbAction.insert(o, propertyPath, dependingOn);
aggregateChange.addAction(insert);
referencedEntities(o).forEach(propertyAndValue -> saveReferencedEntities(propertyAndValue, aggregateChange,
propertyPath.nested(propertyAndValue.property.getName()), insert));
referencedEntities(o) //
.forEach( //
propertyAndValue -> //
insertReferencedEntities( //
propertyAndValue, //
aggregateChange, //
propertyPath.nested(propertyAndValue.property.getName()), //
insert) //
);
} else {
deleteReferencedEntities(entityInformation.getRequiredId(o), aggregateChange);
@ -76,53 +83,13 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport { @@ -76,53 +83,13 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
}
}
private void saveReferencedEntities(PropertyAndValue propertyAndValue, AggregateChange aggregateChange,
JdbcPropertyPath propertyPath, DbAction dependingOn) {
saveActions(propertyAndValue, propertyPath, dependingOn).forEach(a -> {
aggregateChange.addAction(a);
referencedEntities(propertyAndValue.value)
.forEach(pav -> saveReferencedEntities(pav, aggregateChange, propertyPath.nested(pav.property.getName()), a));
});
}
private Stream<DbAction> saveActions(PropertyAndValue propertyAndValue, JdbcPropertyPath propertyPath,
DbAction dependingOn) {
if (Map.Entry.class.isAssignableFrom(ClassUtils.getUserClass(propertyAndValue.value))) {
return mapEntrySaveAction(propertyAndValue, propertyPath, dependingOn);
}
return Stream.of(singleSaveAction(propertyAndValue.value, propertyPath, dependingOn));
}
private Stream<DbAction> mapEntrySaveAction(PropertyAndValue propertyAndValue, JdbcPropertyPath propertyPath,
DbAction dependingOn) {
Map.Entry<Object, Object> entry = (Map.Entry) propertyAndValue.value;
DbAction action = singleSaveAction(entry.getValue(), propertyPath, dependingOn);
action.getAdditionalValues().put(propertyAndValue.property.getKeyColumn(), entry.getKey());
return Stream.of(action);
}
private <T> DbAction singleSaveAction(T t, JdbcPropertyPath propertyPath, DbAction dependingOn) {
JdbcPersistentEntityInformation<T, ?> entityInformation = context
.getRequiredPersistentEntityInformation((Class<T>) ClassUtils.getUserClass(t));
return entityInformation.isNew(t) ? DbAction.insert(t, propertyPath, dependingOn)
: DbAction.update(t, propertyPath, dependingOn);
}
private void insertReferencedEntities(PropertyAndValue propertyAndValue, AggregateChange aggregateChange,
JdbcPropertyPath propertyPath, DbAction dependingOn) {
Insert<Object> insert;
if (propertyAndValue.property.isQualified()) {
Entry<Object, Object> valueAsEntry = (Entry<Object, Object>) propertyAndValue.value;
KeyValue valueAsEntry = (KeyValue) propertyAndValue.value;
insert = DbAction.insert(valueAsEntry.getValue(), propertyPath, dependingOn);
insert.getAdditionalValues().put(propertyAndValue.property.getKeyColumn(), valueAsEntry.getKey());
} else {
@ -130,8 +97,14 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport { @@ -130,8 +97,14 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
}
aggregateChange.addAction(insert);
referencedEntities(insert.getEntity())
.forEach(pav -> insertReferencedEntities(pav, aggregateChange, propertyPath.nested(pav.property.getName()), dependingOn));
referencedEntities(insert.getEntity()) //
.peek(System.out::println)
.forEach(pav -> insertReferencedEntities( //
pav, //
aggregateChange, //
propertyPath.nested(pav.property.getName()), //
dependingOn) //
);
}
private Stream<PropertyAndValue> referencedEntities(Object o) {
@ -189,13 +162,11 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport { @@ -189,13 +162,11 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
if (property == null) return Stream.empty();
// ugly hackery since Java streams don't have a zip method.
AtomicInteger index = new AtomicInteger();
List<Object> listProperty = (List<Object>) property;
HashMap<Integer, Object> map = new HashMap<>();
for (int i = 0; i < listProperty.size(); i++) {
map.put(i, listProperty.get(i));
}
return map.entrySet().stream().map(e -> (Object) e);
return listProperty.stream().map(e -> new KeyValue(index.getAndIncrement(), e));
}
private Stream<Object> mapPropertyAsStream(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {
@ -204,7 +175,7 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport { @@ -204,7 +175,7 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
return property == null //
? Stream.empty() //
: ((Map<Object, Object>) property).entrySet().stream().map(e -> (Object) e);
: ((Map<Object, Object>) property).entrySet().stream().map(e -> new KeyValue(e.getKey(), e.getValue()));
}
private Stream<Object> singlePropertyAsStream(JdbcPersistentProperty p, PersistentPropertyAccessor propertyAccessor) {
@ -217,7 +188,16 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport { @@ -217,7 +188,16 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
return Stream.of(property);
}
@RequiredArgsConstructor
/**
* Holds key and value of a {@link Map.Entry} but without any ties to {@link Map} implementations.
*/
@Data
private static class KeyValue {
private final Object key;
private final Object value;
}
@Data
private static class PropertyAndValue {
private final JdbcPersistentProperty property;

39
src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java

@ -203,6 +203,45 @@ public class JdbcEntityWriterUnitTests { @@ -203,6 +203,45 @@ public class JdbcEntityWriterUnitTests {
);
}
@Test // DATAJDBC-183
public void newEntityWithFullMapResultsInAdditionalInsertPerElement() {
MapContainer entity = new MapContainer(null);
entity.elements.put("1", new Element(null));
entity.elements.put("2", new Element(null));
entity.elements.put("3", new Element(null));
entity.elements.put("4", new Element(null));
entity.elements.put("5", new Element(null));
entity.elements.put("6", new Element(null));
entity.elements.put("7", new Element(null));
entity.elements.put("8", new Element(null));
entity.elements.put("9", new Element(null));
entity.elements.put("0", new Element(null));
entity.elements.put("a", new Element(null));
entity.elements.put("b", new Element(null));
AggregateChange<MapContainer> aggregateChange = new AggregateChange(Kind.SAVE, MapContainer.class, entity);
converter.write(entity, aggregateChange);
assertThat(aggregateChange.getActions())
.extracting(DbAction::getClass, DbAction::getEntityType, this::getMapKey, this::extractPath) //
.containsExactlyInAnyOrder( //
tuple(Insert.class, MapContainer.class, null, ""), //
tuple(Insert.class, Element.class, "1", "elements"), //
tuple(Insert.class, Element.class, "2", "elements"), //
tuple(Insert.class, Element.class, "3", "elements"), //
tuple(Insert.class, Element.class, "4", "elements"), //
tuple(Insert.class, Element.class, "5", "elements"), //
tuple(Insert.class, Element.class, "6", "elements"), //
tuple(Insert.class, Element.class, "7", "elements"), //
tuple(Insert.class, Element.class, "8", "elements"), //
tuple(Insert.class, Element.class, "9", "elements"), //
tuple(Insert.class, Element.class, "0", "elements"), //
tuple(Insert.class, Element.class, "a", "elements"), //
tuple(Insert.class, Element.class, "b", "elements") //
);
}
@Test // DATAJDBC-130
public void newEntityWithEmptyListResultsInSingleInsert() {

Loading…
Cancel
Save