DATAJDBC-137 - Polishing.
Moved the dependency to NamedParameterJdbcOperations out of JdbcMappingContext. This revealed that despite the DataAccessStrategy abstraction, there are a couple of places in the query execution subsystem that work with a plain NamedParameterJdbcOperations instance, so that we now have to carry that around all the way from the repository factory bean. Improving that is subject for further changes. A bit of JavaDoc and generics polish here and there.
This commit is contained in:
@@ -21,7 +21,8 @@ import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
|
||||
/**
|
||||
* Abstraction for accesses to the database that should be implementable with a single SQL statement and relates to a single entity as opposed to {@link JdbcEntityOperations} which provides interactions related to complete aggregates.
|
||||
* Abstraction for accesses to the database that should be implementable with a single SQL statement and relates to a
|
||||
* single entity as opposed to {@link JdbcEntityOperations} which provides interactions related to complete aggregates.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 1.0
|
||||
@@ -68,5 +69,4 @@ public interface DataAccessStrategy {
|
||||
<T> Iterable<T> findAllByProperty(Object rootId, JdbcPersistentProperty property);
|
||||
|
||||
<T> boolean existsById(Object id, Class<T> domainType);
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -46,34 +49,27 @@ import org.springframework.util.Assert;
|
||||
* @author Jens Schauder
|
||||
* @since 1.0
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
|
||||
private static final String ENTITY_NEW_AFTER_INSERT = "Entity [%s] still 'new' after insert. Please set either"
|
||||
+ " the id property in a BeforeInsert event handler, or ensure the database creates a value and your "
|
||||
+ "JDBC driver returns it.";
|
||||
|
||||
private final SqlGeneratorSource sqlGeneratorSource;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
private final JdbcMappingContext context;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
|
||||
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context,
|
||||
DataAccessStrategy accessStrategy) {
|
||||
|
||||
this.sqlGeneratorSource = sqlGeneratorSource;
|
||||
this.operations = context.getTemplate();
|
||||
this.context = context;
|
||||
this.accessStrategy = accessStrategy;
|
||||
}
|
||||
private final @NonNull SqlGeneratorSource sqlGeneratorSource;
|
||||
private final @NonNull JdbcMappingContext context;
|
||||
private final @NonNull DataAccessStrategy accessStrategy;
|
||||
private final @NonNull NamedParameterJdbcOperations operations;
|
||||
|
||||
/**
|
||||
* Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses.
|
||||
* Only suitable if this is the only access strategy in use.
|
||||
*/
|
||||
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context) {
|
||||
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context,
|
||||
NamedParameterJdbcOperations operations) {
|
||||
|
||||
this.sqlGeneratorSource = sqlGeneratorSource;
|
||||
this.operations = context.getTemplate();
|
||||
this.operations = operations;
|
||||
this.context = context;
|
||||
this.accessStrategy = this;
|
||||
}
|
||||
@@ -110,9 +106,12 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
if (idProperty != null && idValue == null && entityInformation.isNew(instance)) {
|
||||
throw new IllegalStateException(String.format(ENTITY_NEW_AFTER_INSERT, persistentEntity));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#update(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <S> void update(S instance, Class<S> domainType) {
|
||||
|
||||
@@ -121,6 +120,10 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
operations.update(sql(domainType).getUpdate(), getPropertyMap(instance, persistentEntity));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#delete(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public void delete(Object id, Class<?> domainType) {
|
||||
|
||||
@@ -130,6 +133,10 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
operations.update(deleteByIdSql, parameter);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#delete(java.lang.Object, org.springframework.data.mapping.PropertyPath)
|
||||
*/
|
||||
@Override
|
||||
public void delete(Object rootId, PropertyPath propertyPath) {
|
||||
|
||||
@@ -145,27 +152,43 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
operations.update(format, parameters);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteAll(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> void deleteAll(Class<T> domainType) {
|
||||
operations.getJdbcOperations().update(sql(domainType).createDeleteAllSql(null));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteAll(org.springframework.data.mapping.PropertyPath)
|
||||
*/
|
||||
@Override
|
||||
public <T> void deleteAll(PropertyPath propertyPath) {
|
||||
operations.getJdbcOperations().update(sql(propertyPath.getOwningType().getType()).createDeleteAllSql(propertyPath));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#count(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public long count(Class<?> domainType) {
|
||||
return operations.getJdbcOperations().queryForObject(sql(domainType).getCount(), Long.class);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findById(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T findById(Object id, Class<T> domainType) {
|
||||
|
||||
String findOneSql = sql(domainType).getFindOne();
|
||||
MapSqlParameterSource parameter = createIdParameterSource(id, domainType);
|
||||
|
||||
try {
|
||||
return operations.queryForObject(findOneSql, parameter, getEntityRowMapper(domainType));
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
@@ -173,11 +196,19 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAll(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Iterable<T> findAll(Class<T> domainType) {
|
||||
return operations.query(sql(domainType).getFindAll(), getEntityRowMapper(domainType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllById(java.lang.Iterable, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType) {
|
||||
|
||||
@@ -194,15 +225,19 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
return operations.query(findAllInListSql, parameter, getEntityRowMapper(domainType));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#findAllByProperty(java.lang.Object, org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Iterable<T> findAllByProperty(Object rootId, JdbcPersistentProperty property) {
|
||||
|
||||
Assert.notNull(rootId, "rootId must not be null.");
|
||||
|
||||
Class<?> actualType = property.getActualType();
|
||||
String findAllByProperty = sql(actualType).getFindAllByProperty(property.getReverseColumnName(),
|
||||
property.getKeyColumn(), property.isOrdered());
|
||||
String findAllByProperty = sql(actualType) //
|
||||
.getFindAllByProperty(property.getReverseColumnName(), property.getKeyColumn(), property.isOrdered());
|
||||
|
||||
MapSqlParameterSource parameter = new MapSqlParameterSource(property.getReverseColumnName(), rootId);
|
||||
|
||||
@@ -211,11 +246,16 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
|
||||
: getEntityRowMapper(actualType));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.DataAccessStrategy#existsById(java.lang.Object, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> boolean existsById(Object id, Class<T> domainType) {
|
||||
|
||||
String existsSql = sql(domainType).getExists();
|
||||
MapSqlParameterSource parameter = createIdParameterSource(id, domainType);
|
||||
|
||||
return operations.queryForObject(existsSql, parameter, Boolean.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
@@ -35,8 +36,6 @@ import org.springframework.data.mapping.PreferredConstructor.Parameter;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Maps a ResultSet to an entity of type {@code T}, including entities referenced.
|
||||
@@ -47,7 +46,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
private static final Converter ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter();
|
||||
private static final Converter<Iterable<?>, Map<?, ?>> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter();
|
||||
|
||||
private final JdbcPersistentEntity<T> entity;
|
||||
private final EntityInstantiator instantiator = new ClassGeneratingEntityInstantiator();
|
||||
@@ -101,14 +100,12 @@ public class EntityRowMapper<T> implements RowMapper<T> {
|
||||
return instantiator.createInstance(entity, new ResultSetParameterValueProvider(rs, entity, conversions, ""));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a single value or a complete Entity from the {@link ResultSet} passed as an argument.
|
||||
*
|
||||
* @param resultSet the {@link ResultSet} to extract the value from. Must not be {@code null}.
|
||||
* @param property the {@link JdbcPersistentProperty} for which the value is intended. Must not be {@code null}.
|
||||
* @param prefix to be used for all column names accessed by this method. Must not be {@code null}.
|
||||
*
|
||||
* @return the value read from the {@link ResultSet}. May be {@code null}.
|
||||
*/
|
||||
private Object readFrom(ResultSet resultSet, JdbcPersistentProperty property, String prefix) {
|
||||
|
||||
@@ -15,27 +15,27 @@
|
||||
*/
|
||||
package org.springframework.data.jdbc.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalConverter;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* A converter for creating a {@link Map} from an {@link Iterable<Map.Entry>}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 1.0
|
||||
*/
|
||||
class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable, Map> {
|
||||
class IterableOfEntryToMapConverter implements ConditionalConverter, Converter<Iterable<?>, Map<?, ?>> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Map convert(Iterable source) {
|
||||
public Map<?, ?> convert(Iterable<?> source) {
|
||||
|
||||
Map result = new HashMap();
|
||||
|
||||
|
||||
@@ -40,5 +40,4 @@ public interface JdbcEntityOperations {
|
||||
<T> Iterable<T> findAll(Class<T> domainType);
|
||||
|
||||
<T> boolean existsById(Object id, Class<T> domainType);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,5 +23,7 @@ import org.springframework.core.convert.support.GenericConversionService;
|
||||
*/
|
||||
public interface ConversionCustomizer {
|
||||
|
||||
public static ConversionCustomizer NONE = __ -> {};
|
||||
|
||||
void customize(GenericConversionService conversions);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link MappingContext} implementation for JDBC.
|
||||
@@ -45,6 +45,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
* @author Jens Schauder
|
||||
* @author Greg Turnquist
|
||||
* @author Kazuki Shimizu
|
||||
* @author Oliver Gierke
|
||||
* @since 1.0
|
||||
*/
|
||||
public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEntity<?>, JdbcPersistentProperty> {
|
||||
@@ -56,24 +57,37 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
|
||||
));
|
||||
|
||||
@Getter private final NamingStrategy namingStrategy;
|
||||
@Getter private final NamedParameterJdbcOperations template;
|
||||
@Getter private SimpleTypeHolder simpleTypeHolder;
|
||||
private GenericConversionService conversions = getDefaultConversionService();
|
||||
|
||||
public JdbcMappingContext(NamingStrategy namingStrategy, NamedParameterJdbcOperations template,
|
||||
ConversionCustomizer customizer) {
|
||||
/**
|
||||
* Creates a new {@link JdbcMappingContext}.
|
||||
*/
|
||||
public JdbcMappingContext() {
|
||||
this(NamingStrategy.INSTANCE, ConversionCustomizer.NONE);
|
||||
}
|
||||
|
||||
public JdbcMappingContext(NamingStrategy namingStrategy) {
|
||||
this(namingStrategy, ConversionCustomizer.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link JdbcMappingContext} using the given {@link NamingStrategy} and {@link ConversionCustomizer}.
|
||||
*
|
||||
* @param namingStrategy must not be {@literal null}.
|
||||
* @param customizer must not be {@literal null}.
|
||||
*/
|
||||
public JdbcMappingContext(NamingStrategy namingStrategy, ConversionCustomizer customizer) {
|
||||
|
||||
Assert.notNull(namingStrategy, "NamingStrategy must not be null!");
|
||||
Assert.notNull(customizer, "ConversionCustomizer must not be null!");
|
||||
|
||||
this.namingStrategy = namingStrategy;
|
||||
this.template = template;
|
||||
|
||||
customizer.customize(conversions);
|
||||
setSimpleTypeHolder(new SimpleTypeHolder(CUSTOM_SIMPLE_TYPES, true));
|
||||
}
|
||||
|
||||
public JdbcMappingContext(NamedParameterJdbcOperations template) {
|
||||
this(NamingStrategy.INSTANCE, template, __ -> {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSimpleTypeHolder(SimpleTypeHolder simpleTypes) {
|
||||
super.setSimpleTypeHolder(simpleTypes);
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.jdbc.core.SqlGeneratorSource;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -43,6 +44,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Kazuki Shimizu
|
||||
* @author Oliver Gierke
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
@@ -54,16 +56,17 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
* Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one
|
||||
* uses a {@link DefaultDataAccessStrategy}
|
||||
*/
|
||||
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) {
|
||||
return createCombinedAccessStrategy(context, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE);
|
||||
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context,
|
||||
NamedParameterJdbcOperations operations, SqlSession sqlSession) {
|
||||
return createCombinedAccessStrategy(context, operations, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one
|
||||
* uses a {@link DefaultDataAccessStrategy}
|
||||
*/
|
||||
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession,
|
||||
NamespaceStrategy namespaceStrategy) {
|
||||
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context,
|
||||
NamedParameterJdbcOperations operations, SqlSession sqlSession, NamespaceStrategy namespaceStrategy) {
|
||||
|
||||
// the DefaultDataAccessStrategy needs a reference to the returned DataAccessStrategy. This creates a dependency
|
||||
// cycle. In order to create it, we need something that allows to defer closing the cycle until all the elements are
|
||||
@@ -75,10 +78,9 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy(
|
||||
asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy));
|
||||
|
||||
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy( //
|
||||
new SqlGeneratorSource(context), //
|
||||
context, //
|
||||
cascadingDataAccessStrategy);
|
||||
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(context);
|
||||
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, context,
|
||||
cascadingDataAccessStrategy, operations);
|
||||
|
||||
delegatingDataAccessStrategy.setDelegate(defaultDataAccessStrategy);
|
||||
|
||||
@@ -152,12 +154,12 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
|
||||
@Override
|
||||
public <T> void deleteAll(PropertyPath propertyPath) {
|
||||
|
||||
Class baseType = propertyPath.getOwningType().getType();
|
||||
Class leaveType = propertyPath.getLeafProperty().getTypeInformation().getType();
|
||||
Class<?> baseType = propertyPath.getOwningType().getType();
|
||||
Class<?> leafType = propertyPath.getLeafProperty().getTypeInformation().getType();
|
||||
|
||||
sqlSession().delete( //
|
||||
namespace(baseType) + ".deleteAll-" + toDashPath(propertyPath), //
|
||||
new MyBatisContext(null, null, leaveType, Collections.emptyMap()) //
|
||||
new MyBatisContext(null, null, leafType, Collections.emptyMap()) //
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jdbc.mapping.model.ConversionCustomizer;
|
||||
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
|
||||
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
|
||||
/**
|
||||
* Beans that must be registered for Spring Data JDBC to work.
|
||||
@@ -36,10 +34,10 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
public class JdbcConfiguration {
|
||||
|
||||
@Bean
|
||||
JdbcMappingContext jdbcMappingContext(NamedParameterJdbcOperations template, Optional<NamingStrategy> namingStrategy,
|
||||
JdbcMappingContext jdbcMappingContext(Optional<NamingStrategy> namingStrategy,
|
||||
Optional<ConversionCustomizer> conversionCustomizer) {
|
||||
|
||||
return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE), template,
|
||||
conversionCustomizer.orElse(conversionService -> {}));
|
||||
return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE),
|
||||
conversionCustomizer.orElse(ConversionCustomizer.NONE));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SingleColumnRowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -45,6 +46,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
private final RowMapperMap rowMapperMap;
|
||||
private final ConversionService conversionService;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JdbcQueryLookupStrategy} for the given {@link JdbcMappingContext}, {@link DataAccessStrategy}
|
||||
@@ -54,7 +56,8 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
* @param accessStrategy must not be {@literal null}.
|
||||
* @param rowMapperMap must not be {@literal null}.
|
||||
*/
|
||||
JdbcQueryLookupStrategy(JdbcMappingContext context, DataAccessStrategy accessStrategy, RowMapperMap rowMapperMap) {
|
||||
JdbcQueryLookupStrategy(JdbcMappingContext context, DataAccessStrategy accessStrategy, RowMapperMap rowMapperMap,
|
||||
NamedParameterJdbcOperations operations) {
|
||||
|
||||
Assert.notNull(context, "JdbcMappingContext must not be null!");
|
||||
Assert.notNull(accessStrategy, "DataAccessStrategy must not be null!");
|
||||
@@ -64,6 +67,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
this.accessStrategy = accessStrategy;
|
||||
this.rowMapperMap = rowMapperMap;
|
||||
this.conversionService = context.getConversions();
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -78,7 +82,7 @@ class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
RowMapper<?> rowMapper = queryMethod.isModifyingQuery() ? null : createRowMapper(queryMethod);
|
||||
|
||||
return new JdbcRepositoryQuery(queryMethod, context, rowMapper);
|
||||
return new JdbcRepositoryQuery(queryMethod, operations, rowMapper);
|
||||
}
|
||||
|
||||
private RowMapper<?> createRowMapper(JdbcQueryMethod queryMethod) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -45,6 +46,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
private final JdbcMappingContext context;
|
||||
private final ApplicationEventPublisher publisher;
|
||||
private final DataAccessStrategy accessStrategy;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
|
||||
private RowMapperMap rowMapperMap = RowMapperMap.EMPTY;
|
||||
|
||||
@@ -55,9 +57,10 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
* @param dataAccessStrategy must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
* @param publisher must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
*/
|
||||
public JdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy, JdbcMappingContext context,
|
||||
ApplicationEventPublisher publisher) {
|
||||
ApplicationEventPublisher publisher, NamedParameterJdbcOperations operations) {
|
||||
|
||||
Assert.notNull(dataAccessStrategy, "DataAccessStrategy must not be null!");
|
||||
Assert.notNull(context, "JdbcMappingContext must not be null!");
|
||||
@@ -66,6 +69,7 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
this.publisher = publisher;
|
||||
this.context = context;
|
||||
this.accessStrategy = dataAccessStrategy;
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,6 +127,6 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
|
||||
throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
|
||||
}
|
||||
|
||||
return Optional.of(new JdbcQueryLookupStrategy(context, accessStrategy, rowMapperMap));
|
||||
return Optional.of(new JdbcQueryLookupStrategy(context, accessStrategy, rowMapperMap, operations));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.data.jdbc.repository.RowMapperMap;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -47,6 +48,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
private JdbcMappingContext mappingContext;
|
||||
private DataAccessStrategy dataAccessStrategy;
|
||||
private RowMapperMap rowMapperMap = RowMapperMap.EMPTY;
|
||||
private NamedParameterJdbcOperations operations;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface.
|
||||
@@ -78,7 +80,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
protected RepositoryFactorySupport doCreateRepositoryFactory() {
|
||||
|
||||
JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory(dataAccessStrategy, mappingContext,
|
||||
publisher);
|
||||
publisher, operations);
|
||||
jdbcRepositoryFactory.setRowMapperMap(rowMapperMap);
|
||||
|
||||
return jdbcRepositoryFactory;
|
||||
@@ -108,6 +110,11 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
this.rowMapperMap = rowMapperMap;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setJdbcOperations(NamedParameterJdbcOperations operations) {
|
||||
this.operations = operations;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet()
|
||||
@@ -120,7 +127,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
|
||||
if (dataAccessStrategy == null) {
|
||||
|
||||
SqlGeneratorSource sqlGeneratorSource = new SqlGeneratorSource(mappingContext);
|
||||
this.dataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, mappingContext);
|
||||
this.dataAccessStrategy = new DefaultDataAccessStrategy(sqlGeneratorSource, mappingContext, operations);
|
||||
}
|
||||
|
||||
if (rowMapperMap == null) {
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -38,7 +39,7 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
private static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to provide names for method parameters. Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters.";
|
||||
|
||||
private final JdbcQueryMethod queryMethod;
|
||||
private final JdbcMappingContext context;
|
||||
private final NamedParameterJdbcOperations operations;
|
||||
private final RowMapper<?> rowMapper;
|
||||
|
||||
/**
|
||||
@@ -46,20 +47,21 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
* {@link RowMapper}.
|
||||
*
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
* @param context must not be {@literal null}.
|
||||
* @param operations must not be {@literal null}.
|
||||
* @param defaultRowMapper can be {@literal null} (only in case of a modifying query).
|
||||
*/
|
||||
JdbcRepositoryQuery(JdbcQueryMethod queryMethod, JdbcMappingContext context, RowMapper<?> defaultRowMapper) {
|
||||
JdbcRepositoryQuery(JdbcQueryMethod queryMethod, NamedParameterJdbcOperations operations,
|
||||
RowMapper<?> defaultRowMapper) {
|
||||
|
||||
Assert.notNull(queryMethod, "Query method must not be null!");
|
||||
Assert.notNull(context, "JdbcMappingContext must not be null!");
|
||||
Assert.notNull(operations, "NamedParameterJdbcOperations must not be null!");
|
||||
|
||||
if (!queryMethod.isModifyingQuery()) {
|
||||
Assert.notNull(defaultRowMapper, "RowMapper must not be null!");
|
||||
}
|
||||
|
||||
this.queryMethod = queryMethod;
|
||||
this.context = context;
|
||||
this.operations = operations;
|
||||
this.rowMapper = createRowMapper(queryMethod, defaultRowMapper);
|
||||
}
|
||||
|
||||
@@ -75,18 +77,18 @@ class JdbcRepositoryQuery implements RepositoryQuery {
|
||||
|
||||
if (queryMethod.isModifyingQuery()) {
|
||||
|
||||
int updatedCount = context.getTemplate().update(query, parameters);
|
||||
int updatedCount = operations.update(query, parameters);
|
||||
Class<?> returnedObjectType = queryMethod.getReturnedObjectType();
|
||||
return (returnedObjectType == boolean.class || returnedObjectType == Boolean.class) ? updatedCount != 0
|
||||
: updatedCount;
|
||||
}
|
||||
|
||||
if (queryMethod.isCollectionQuery() || queryMethod.isStreamQuery()) {
|
||||
return context.getTemplate().query(query, parameters, rowMapper);
|
||||
return operations.query(query, parameters, rowMapper);
|
||||
}
|
||||
|
||||
try {
|
||||
return context.getTemplate().queryForObject(query, parameters, rowMapper);
|
||||
return operations.queryForObject(query, parameters, rowMapper);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user