Skip to content

Commit a8c3d6c

Browse files
committed
Move logic for creating SqlParamterSource for insert and update into its own class.
+ To focus DefaultDataAccessStrategy tests on the influence of insert parameters on how it collaborates with JdbcOperations
1 parent 266b818 commit a8c3d6c

File tree

10 files changed

+396
-274
lines changed

10 files changed

+396
-274
lines changed

spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/DefaultDataAccessStrategy.java

Lines changed: 16 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
7676
private final JdbcConverter converter;
7777
private final NamedParameterJdbcOperations operations;
7878
private final BatchJdbcOperations batchOperations;
79+
private final SqlParametersFactory sqlParametersFactory;
7980

8081
/**
8182
* Creates a {@link DefaultDataAccessStrategy}
@@ -87,24 +88,26 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
8788
* @since 1.1
8889
*/
8990
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context,
90-
JdbcConverter converter, NamedParameterJdbcOperations operations) {
91-
this(sqlGeneratorSource, context, converter, operations, new BatchJdbcOperations(operations.getJdbcOperations()));
91+
JdbcConverter converter, NamedParameterJdbcOperations operations, SqlParametersFactory sqlParametersFactory) {
92+
this(sqlGeneratorSource, context, converter, operations, new BatchJdbcOperations(operations.getJdbcOperations()), sqlParametersFactory);
9293
}
9394

9495
DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, RelationalMappingContext context,
9596
JdbcConverter converter, NamedParameterJdbcOperations operations,
96-
BatchJdbcOperations batchOperations) {
97+
BatchJdbcOperations batchOperations, SqlParametersFactory sqlParametersFactory) {
9798

9899
Assert.notNull(sqlGeneratorSource, "SqlGeneratorSource must not be null");
99100
Assert.notNull(context, "RelationalMappingContext must not be null");
100101
Assert.notNull(converter, "JdbcConverter must not be null");
101102
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null");
103+
Assert.notNull(sqlParametersFactory, "SqlParametersFactory must not be null");
102104

103105
this.sqlGeneratorSource = sqlGeneratorSource;
104106
this.context = context;
105107
this.converter = converter;
106108
this.operations = operations;
107109
this.batchOperations = batchOperations;
110+
this.sqlParametersFactory = sqlParametersFactory;
108111
}
109112

110113
/*
@@ -114,24 +117,12 @@ public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, Relation
114117
@Override
115118
public <T> Object insert(T instance, Class<T> domainType, Identifier identifier, boolean includeId) {
116119

117-
SqlGenerator sqlGenerator = sql(domainType);
118-
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
119-
120-
SqlIdentifierParameterSource parameterSource = getParameterSource(instance, persistentEntity, "",
121-
PersistentProperty::isIdProperty, getIdentifierProcessing());
122-
123-
identifier.forEach((name, value, type) -> addConvertedPropertyValue(parameterSource, name, value, type));
124-
125-
Object idValue = getIdValueOrNull(instance, persistentEntity);
126-
if (idValue != null) {
120+
SqlIdentifierParameterSource parameterSource = sqlParametersFactory.getInsert(instance, domainType, identifier);
127121

128-
RelationalPersistentProperty idProperty = persistentEntity.getRequiredIdProperty();
129-
addConvertedPropertyValue(parameterSource, idProperty, idValue, idProperty.getColumnName());
130-
}
131-
132-
String insertSql = sqlGenerator.getInsert(parameterSource.getIdentifiers());
122+
String insertSql = sql(domainType).getInsert(parameterSource.getIdentifiers());
133123

134124
if (!includeId) {
125+
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
135126
return executeInsertAndReturnGeneratedId(persistentEntity, parameterSource, insertSql);
136127
} else {
137128

@@ -145,9 +136,8 @@ public <T> Object[] insert(List<RecordDescriptor<T>> recordDescriptors, Class<T>
145136
// TODO: A better name for this may be the inverse (generatedIdExpected)
146137
boolean includeId) {
147138

148-
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
149139
SqlIdentifierParameterSource[] sqlParameterSources = recordDescriptors.stream()
150-
.map(recordDescriptor -> getParameterSource(recordDescriptor, persistentEntity))
140+
.map(recordDescriptor -> sqlParametersFactory.getInsert(recordDescriptor.getInstance(), domainType, recordDescriptor.getIdentifier()))
151141
.toArray(SqlIdentifierParameterSource[]::new);
152142

153143
String insertSql = sql(domainType).getInsert(sqlParameterSources[0].getIdentifiers());
@@ -160,6 +150,7 @@ public <T> Object[] insert(List<RecordDescriptor<T>> recordDescriptors, Class<T>
160150

161151
IdGeneration idGeneration = sqlGeneratorSource.getDialect().getIdGeneration();
162152

153+
RelationalPersistentEntity<T> persistentEntity = getRequiredPersistentEntity(domainType);
163154
if (idGeneration.driverRequiresKeyColumnNames()) {
164155

165156
String[] keyColumnNames = getKeyColumnNames(persistentEntity.getType());
@@ -171,6 +162,7 @@ public <T> Object[] insert(List<RecordDescriptor<T>> recordDescriptors, Class<T>
171162
} else {
172163
batchOperations.insert(insertSql, sqlParameterSources, holder);
173164
}
165+
// TODO: Is this needed?
174166
if (!persistentEntity.hasIdProperty()) {
175167
return new Object[sqlParameterSources.length];
176168
}
@@ -185,29 +177,13 @@ public <T> Object[] insert(List<RecordDescriptor<T>> recordDescriptors, Class<T>
185177
} else {
186178
id = keys.entrySet().stream().findFirst() //
187179
.map(Map.Entry::getValue) //
188-
// TODO: Missing a test for this
189-
.orElse(null);
180+
.orElseThrow(() -> new IllegalStateException("KeyHolder contains an empty key list."));
190181
}
191182
ids[i] = id;
192183
}
193184
return ids;
194185
}
195186

196-
private <T> SqlIdentifierParameterSource getParameterSource(RecordDescriptor<T> recordDescriptor, RelationalPersistentEntity<T> persistentEntity) {
197-
SqlIdentifierParameterSource parameterSource = getParameterSource(recordDescriptor.getInstance(), persistentEntity, "",
198-
PersistentProperty::isIdProperty, getIdentifierProcessing());
199-
200-
recordDescriptor.getIdentifier().forEach((name, value, type) -> addConvertedPropertyValue(parameterSource, name, value, type));
201-
202-
Object idValue = getIdValueOrNull(recordDescriptor.getInstance(), persistentEntity);
203-
if (idValue != null) {
204-
205-
RelationalPersistentProperty idProperty = persistentEntity.getRequiredIdProperty();
206-
addConvertedPropertyValue(parameterSource, idProperty, idValue, idProperty.getColumnName());
207-
}
208-
return parameterSource;
209-
}
210-
211187
@Nullable
212188
private <T> Object executeInsertAndReturnGeneratedId(RelationalPersistentEntity<T> persistentEntity, SqlIdentifierParameterSource parameterSource, String insertSql) {
213189

@@ -236,10 +212,7 @@ private <T> Object executeInsertAndReturnGeneratedId(RelationalPersistentEntity<
236212
*/
237213
@Override
238214
public <S> boolean update(S instance, Class<S> domainType) {
239-
240-
RelationalPersistentEntity<S> persistentEntity = getRequiredPersistentEntity(domainType);
241-
return operations.update(sql(domainType).getUpdate(),
242-
getParameterSource(instance, persistentEntity, "", Predicates.includeAll(), getIdentifierProcessing())) != 0;
215+
return operations.update(sql(domainType).getUpdate(), sqlParametersFactory.getUpdate(instance, domainType)) != 0;
243216
}
244217

245218
/*
@@ -252,8 +225,7 @@ public <S> boolean updateWithVersion(S instance, Class<S> domainType, Number pre
252225
RelationalPersistentEntity<S> persistentEntity = getRequiredPersistentEntity(domainType);
253226

254227
// Adjust update statement to set the new version and use the old version in where clause.
255-
SqlIdentifierParameterSource parameterSource = getParameterSource(instance, persistentEntity, "",
256-
Predicates.includeAll(), getIdentifierProcessing());
228+
SqlIdentifierParameterSource parameterSource = sqlParametersFactory.getUpdate(instance, domainType);
257229
parameterSource.addValue(VERSION_SQL_PARAMETER, previousVersion);
258230

259231
int affectedRows = operations.update(sql(domainType).getUpdateWithVersion(), parameterSource);
@@ -504,67 +476,6 @@ public <T> Iterable<T> findAll(Class<T> domainType, Pageable pageable) {
504476
return operations.query(sql(domainType).getFindAll(pageable), (RowMapper<T>) getEntityRowMapper(domainType));
505477
}
506478

507-
private <S, T> SqlIdentifierParameterSource getParameterSource(@Nullable S instance,
508-
RelationalPersistentEntity<S> persistentEntity, String prefix,
509-
Predicate<RelationalPersistentProperty> skipProperty, IdentifierProcessing identifierProcessing) {
510-
511-
SqlIdentifierParameterSource parameters = new SqlIdentifierParameterSource(identifierProcessing);
512-
513-
PersistentPropertyAccessor<S> propertyAccessor = instance != null ? persistentEntity.getPropertyAccessor(instance)
514-
: NoValuePropertyAccessor.instance();
515-
516-
persistentEntity.doWithAll(property -> {
517-
518-
if (skipProperty.test(property) || !property.isWritable()) {
519-
return;
520-
}
521-
if (property.isEntity() && !property.isEmbedded()) {
522-
return;
523-
}
524-
525-
if (property.isEmbedded()) {
526-
527-
Object value = propertyAccessor.getProperty(property);
528-
RelationalPersistentEntity<?> embeddedEntity = context.getPersistentEntity(property.getType());
529-
SqlIdentifierParameterSource additionalParameters = getParameterSource((T) value,
530-
(RelationalPersistentEntity<T>) embeddedEntity, prefix + property.getEmbeddedPrefix(), skipProperty,
531-
identifierProcessing);
532-
parameters.addAll(additionalParameters);
533-
} else {
534-
535-
Object value = propertyAccessor.getProperty(property);
536-
SqlIdentifier paramName = property.getColumnName().transform(prefix::concat);
537-
538-
addConvertedPropertyValue(parameters, property, value, paramName);
539-
}
540-
});
541-
542-
return parameters;
543-
}
544-
545-
/**
546-
* Returns the id value if its not a primitive zero. Returns {@literal null} if the id value is null or a primitive
547-
* zero.
548-
*/
549-
@Nullable
550-
@SuppressWarnings("unchecked")
551-
private <S, ID> ID getIdValueOrNull(S instance, RelationalPersistentEntity<S> persistentEntity) {
552-
553-
ID idValue = (ID) persistentEntity.getIdentifierAccessor(instance).getIdentifier();
554-
555-
return isIdPropertyNullOrScalarZero(idValue, persistentEntity) ? null : idValue;
556-
}
557-
558-
private static <S, ID> boolean isIdPropertyNullOrScalarZero(@Nullable ID idValue,
559-
RelationalPersistentEntity<S> persistentEntity) {
560-
561-
RelationalPersistentProperty idProperty = persistentEntity.getIdProperty();
562-
return idValue == null //
563-
|| idProperty == null //
564-
|| (idProperty.getType() == int.class && idValue.equals(0)) //
565-
|| (idProperty.getType() == long.class && idValue.equals(0L));
566-
}
567-
568479
@Nullable
569480
private <S> Object getIdFromHolder(KeyHolder holder, RelationalPersistentEntity<S> persistentEntity) {
570481

@@ -601,6 +512,7 @@ private RowMapper<?> getMapEntityRowMapper(PersistentPropertyPathExtension path,
601512
return new MapEntityRowMapper<>(path, converter, identifier, keyColumn, getIdentifierProcessing());
602513
}
603514

515+
// TODO: Move to SqlParametersFactory
604516
private <T> SqlIdentifierParameterSource createIdParameterSource(Object id, Class<T> domainType) {
605517

606518
SqlIdentifierParameterSource parameterSource = new SqlIdentifierParameterSource(getIdentifierProcessing());
@@ -689,47 +601,4 @@ private <T> String[] getKeyColumnNames(Class<T> domainType) {
689601
return new String[] { idColumn.getReference(getIdentifierProcessing()) };
690602
}
691603

692-
/**
693-
* Utility to create {@link Predicate}s.
694-
*/
695-
static class Predicates {
696-
697-
/**
698-
* Include all {@link Predicate} returning {@literal false} to never skip a property.
699-
*
700-
* @return the include all {@link Predicate}.
701-
*/
702-
static Predicate<RelationalPersistentProperty> includeAll() {
703-
return it -> false;
704-
}
705-
}
706-
707-
/**
708-
* A {@link PersistentPropertyAccessor} implementation always returning null
709-
*
710-
* @param <T>
711-
*/
712-
static class NoValuePropertyAccessor<T> implements PersistentPropertyAccessor<T> {
713-
714-
private static final NoValuePropertyAccessor INSTANCE = new NoValuePropertyAccessor();
715-
716-
static <T> NoValuePropertyAccessor<T> instance() {
717-
return INSTANCE;
718-
}
719-
720-
@Override
721-
public void setProperty(PersistentProperty<?> property, @Nullable Object value) {
722-
throw new UnsupportedOperationException("Cannot set value on 'null' target object.");
723-
}
724-
725-
@Override
726-
public Object getProperty(PersistentProperty<?> property) {
727-
return null;
728-
}
729-
730-
@Override
731-
public T getBean() {
732-
return null;
733-
}
734-
}
735604
}

0 commit comments

Comments
 (0)