diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutionContext.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutionContext.java
index ed67dfdfb4..8c37babdd0 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutionContext.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateChangeExecutionContext.java
@@ -15,7 +15,16 @@
*/
package org.springframework.data.jdbc.core;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
@@ -33,7 +42,6 @@
import org.springframework.data.relational.core.conversion.DbActionExecutionResult;
import org.springframework.data.relational.core.conversion.IdValueSource;
import org.springframework.data.relational.core.mapping.AggregatePath;
-import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
@@ -188,7 +196,8 @@ private Identifier getParentKeys(DbAction.WithDependingOn> action, JdbcConvert
private Object getParentId(DbAction.WithDependingOn> action) {
- DbAction.WithEntity> idOwningAction = getIdOwningAction(action, context.getAggregatePath(action.getPropertyPath()).getIdDefiningParentPath());
+ DbAction.WithEntity> idOwningAction = getIdOwningAction(action,
+ context.getAggregatePath(action.getPropertyPath()).getIdDefiningParentPath());
return getPotentialGeneratedIdFrom(idOwningAction);
}
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java
index c57125233c..32d66d0b9d 100644
--- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/convert/BasicJdbcConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2023 the original author or authors.
+ * Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,78 +15,25 @@
*/
package org.springframework.data.jdbc.core.convert;
-import java.sql.Array;
-import java.sql.JDBCType;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.SQLType;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.core.convert.ConverterNotFoundException;
-import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.CustomConversions;
-import org.springframework.data.jdbc.core.mapping.AggregateReference;
-import org.springframework.data.jdbc.core.mapping.JdbcValue;
-import org.springframework.data.jdbc.support.JdbcUtil;
-import org.springframework.data.mapping.InstanceCreatorMetadata;
-import org.springframework.data.mapping.Parameter;
-import org.springframework.data.mapping.PersistentPropertyAccessor;
-import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.context.MappingContext;
-import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
-import org.springframework.data.mapping.model.ParameterValueProvider;
-import org.springframework.data.mapping.model.SimpleTypeHolder;
-import org.springframework.data.mapping.model.SpELContext;
-import org.springframework.data.mapping.model.SpELExpressionEvaluator;
-import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
-import org.springframework.data.projection.EntityProjection;
-import org.springframework.data.relational.core.conversion.MappingRelationalConverter;
-import org.springframework.data.relational.core.conversion.ObjectPath;
import org.springframework.data.relational.core.conversion.RelationalConverter;
-import org.springframework.data.relational.core.conversion.RowDocumentAccessor;
-import org.springframework.data.relational.core.mapping.AggregatePath;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
-import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
-import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
-import org.springframework.data.relational.domain.RowDocument;
-import org.springframework.data.util.TypeInformation;
-import org.springframework.lang.Nullable;
-import org.springframework.util.Assert;
/**
- * {@link RelationalConverter} that uses a {@link MappingContext} to apply basic conversion of relational values to
- * property values.
+ * {@link RelationalConverter} that uses a {@link MappingContext} to apply conversion of relational values to property
+ * values.
*
* Conversion is configurable by providing a customized {@link CustomConversions}.
*
* @author Mark Paluch
- * @author Jens Schauder
- * @author Christoph Strobl
- * @author Myeonghyeon Lee
- * @author Chirag Tailor
- * @see MappingContext
- * @see SimpleTypeHolder
- * @see CustomConversions
* @since 1.1
+ * @deprecated since 3.2, use {@link MappingJdbcConverter} instead as the naming suggests a limited scope of
+ * functionality.
*/
-public class BasicJdbcConverter extends MappingRelationalConverter implements JdbcConverter, ApplicationContextAware {
-
- private static final Log LOG = LogFactory.getLog(BasicJdbcConverter.class);
- private static final Converter, Map, ?>> ITERABLE_OF_ENTRY_TO_MAP_CONVERTER = new IterableOfEntryToMapConverter();
-
- private final JdbcTypeFactory typeFactory;
- private final IdentifierProcessing identifierProcessing;
-
- private final RelationResolver relationResolver;
- private SpELContext spELContext;
+@Deprecated(since = "3.2")
+public class BasicJdbcConverter extends MappingJdbcConverter {
/**
* Creates a new {@link BasicJdbcConverter} given {@link MappingContext} and a {@link JdbcTypeFactory#unsupported()
@@ -98,15 +45,7 @@ public class BasicJdbcConverter extends MappingRelationalConverter implements Jd
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
*/
public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver) {
-
- super(context, new JdbcCustomConversions());
-
- Assert.notNull(relationResolver, "RelationResolver must not be null");
-
- this.typeFactory = JdbcTypeFactory.unsupported();
- this.identifierProcessing = IdentifierProcessing.ANSI;
- this.relationResolver = relationResolver;
- this.spELContext = new SpELContext(ResultSetAccessorPropertyAccessor.INSTANCE);
+ super(context, relationResolver);
}
/**
@@ -115,719 +54,24 @@ public BasicJdbcConverter(RelationalMappingContext context, RelationResolver rel
* @param context must not be {@literal null}.
* @param relationResolver used to fetch additional relations from the database. Must not be {@literal null}.
* @param typeFactory must not be {@literal null}
- * @param identifierProcessing must not be {@literal null}
- * @since 2.0
+ * @since 3.2
*/
public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
- CustomConversions conversions, JdbcTypeFactory typeFactory, IdentifierProcessing identifierProcessing) {
-
- super(context, conversions);
-
- Assert.notNull(typeFactory, "JdbcTypeFactory must not be null");
- Assert.notNull(relationResolver, "RelationResolver must not be null");
- Assert.notNull(identifierProcessing, "IdentifierProcessing must not be null");
-
- this.typeFactory = typeFactory;
- this.identifierProcessing = identifierProcessing;
- this.relationResolver = relationResolver;
- this.spELContext = new SpELContext(ResultSetAccessorPropertyAccessor.INSTANCE);
- }
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) {
- this.spELContext = new SpELContext(this.spELContext, applicationContext);
- }
-
- @Nullable
- private Class> getEntityColumnType(Class> type) {
-
- RelationalPersistentEntity> persistentEntity = getMappingContext().getPersistentEntity(type);
-
- if (persistentEntity == null) {
- return null;
- }
-
- RelationalPersistentProperty idProperty = persistentEntity.getIdProperty();
-
- if (idProperty == null) {
- return null;
- }
- return getColumnType(idProperty);
- }
-
- private Class> getReferenceColumnType(RelationalPersistentProperty property) {
-
- Class> componentType = property.getTypeInformation().getRequiredComponentType().getType();
- RelationalPersistentEntity> referencedEntity = getMappingContext().getRequiredPersistentEntity(componentType);
-
- return getColumnType(referencedEntity.getRequiredIdProperty());
- }
-
- @Override
- public SQLType getTargetSqlType(RelationalPersistentProperty property) {
- return JdbcUtil.targetSqlTypeFor(getColumnType(property));
- }
-
- @Override
- public Class> getColumnType(RelationalPersistentProperty property) {
- return doGetColumnType(property);
- }
-
- private Class> doGetColumnType(RelationalPersistentProperty property) {
-
- if (property.isAssociation()) {
- return getReferenceColumnType(property);
- }
-
- if (property.isEntity()) {
- Class> columnType = getEntityColumnType(property.getActualType());
-
- if (columnType != null) {
- return columnType;
- }
- }
-
- Class> componentColumnType = JdbcColumnTypes.INSTANCE.resolvePrimitiveType(property.getActualType());
-
- while (componentColumnType.isArray()) {
- componentColumnType = componentColumnType.getComponentType();
- }
-
- if (property.isCollectionLike() && !property.isEntity()) {
- return java.lang.reflect.Array.newInstance(componentColumnType, 0).getClass();
- }
-
- return componentColumnType;
- }
-
- @Override
- @Nullable
- public Object readValue(@Nullable Object value, TypeInformation> type) {
-
- if (value == null) {
- return value;
- }
-
- if (value instanceof Array) {
- try {
- return super.readValue(((Array) value).getArray(), type);
- } catch (SQLException | ConverterNotFoundException e) {
- LOG.info("Failed to extract a value of type %s from an Array; Attempting to use standard conversions", e);
- }
- }
-
- return super.readValue(value, type);
- }
-
- @Override
- @Nullable
- public Object writeValue(@Nullable Object value, TypeInformation> type) {
-
- if (value == null) {
- return null;
- }
-
- return super.writeValue(value, type);
- }
-
- private boolean canWriteAsJdbcValue(@Nullable Object value) {
-
- if (value == null) {
- return true;
- }
-
- if (AggregateReference.class.isAssignableFrom(value.getClass())) {
- return canWriteAsJdbcValue(((AggregateReference) value).getId());
- }
-
- RelationalPersistentEntity> persistentEntity = getMappingContext().getPersistentEntity(value.getClass());
-
- if (persistentEntity != null) {
-
- Object id = persistentEntity.getIdentifierAccessor(value).getIdentifier();
- return canWriteAsJdbcValue(id);
- }
-
- if (value instanceof JdbcValue) {
- return true;
- }
-
- Optional> customWriteTarget = getConversions().getCustomWriteTarget(value.getClass());
- return customWriteTarget.isPresent() && customWriteTarget.get().isAssignableFrom(JdbcValue.class);
- }
-
- @Override
- public JdbcValue writeJdbcValue(@Nullable Object value, Class> columnType, SQLType sqlType) {
-
- JdbcValue jdbcValue = tryToConvertToJdbcValue(value);
- if (jdbcValue != null) {
- return jdbcValue;
- }
-
- Object convertedValue = writeValue(value, TypeInformation.of(columnType));
-
- if (convertedValue == null || !convertedValue.getClass().isArray()) {
-
- return JdbcValue.of(convertedValue, sqlType);
- }
-
- Class> componentType = convertedValue.getClass().getComponentType();
- if (componentType != byte.class && componentType != Byte.class) {
-
- Object[] objectArray = requireObjectArray(convertedValue);
- return JdbcValue.of(typeFactory.createArray(objectArray), JDBCType.ARRAY);
- }
-
- if (componentType == Byte.class) {
- convertedValue = ArrayUtils.toPrimitive((Byte[]) convertedValue);
- }
-
- return JdbcValue.of(convertedValue, JDBCType.BINARY);
- }
-
- @Nullable
- private JdbcValue tryToConvertToJdbcValue(@Nullable Object value) {
-
- if (canWriteAsJdbcValue(value)) {
-
- Object converted = writeValue(value, TypeInformation.of(JdbcValue.class));
- if (converted instanceof JdbcValue) {
- return (JdbcValue) converted;
- }
- }
-
- return null;
- }
-
- @Override
- public T mapRow(RelationalPersistentEntity entity, ResultSet resultSet, Object key) {
- return new ReadingContext(getMappingContext().getAggregatePath(entity), new ResultSetAccessor(resultSet),
- Identifier.empty(), key).mapRow();
- }
-
- @Override
- public T mapRow(AggregatePath path, ResultSet resultSet, Identifier identifier, Object key) {
- return new ReadingContext(path, new ResultSetAccessor(resultSet), identifier, key).mapRow();
- }
-
- @Override
- public R projectAndResolve(EntityProjection projection, RowDocument document) {
-
- RelationalPersistentEntity> entity = getMappingContext()
- .getRequiredPersistentEntity(projection.getActualDomainType());
- ResolvingConversionContext context = new ResolvingConversionContext(newProjectingConversionContext(projection),
- getMappingContext().getAggregatePath(entity), Identifier.empty());
-
- return doReadProjection(context, document, projection);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public R readAndResolve(Class type, RowDocument source, Identifier identifier) {
-
- RelationalPersistentEntity entity = (RelationalPersistentEntity) getMappingContext()
- .getRequiredPersistentEntity(type);
- AggregatePath path = getMappingContext().getAggregatePath(entity);
- Identifier identifierToUse = ResolvingRelationalPropertyValueProvider.potentiallyAppendIdentifier(identifier,
- entity, it -> source.get(it.getColumnName().getReference()));
- ResolvingConversionContext context = new ResolvingConversionContext(getConversionContext(ObjectPath.ROOT), path,
- identifierToUse);
-
- return readAggregate(context, source, entity.getTypeInformation());
- }
-
- @Override
- protected RelationalPropertyValueProvider newValueProvider(RowDocumentAccessor documentAccessor,
- SpELExpressionEvaluator evaluator, ConversionContext context) {
-
- if (context instanceof ResolvingConversionContext rcc) {
-
- AggregatePathValueProvider delegate = (AggregatePathValueProvider) super.newValueProvider(documentAccessor,
- evaluator, context);
-
- return new ResolvingRelationalPropertyValueProvider(delegate, documentAccessor, rcc, rcc.identifier());
- }
-
- return super.newValueProvider(documentAccessor, evaluator, context);
+ CustomConversions conversions, JdbcTypeFactory typeFactory) {
+ super(context, relationResolver, conversions, typeFactory);
}
/**
- * {@link RelationalPropertyValueProvider} using a resolving context to lookup relations. This is highly
- * context-sensitive. Note that the identifier is held here because of a chicken and egg problem, while
- * {@link ResolvingConversionContext} hols the {@link AggregatePath}.
- */
- class ResolvingRelationalPropertyValueProvider implements RelationalPropertyValueProvider {
-
- private final AggregatePathValueProvider delegate;
-
- private final RowDocumentAccessor accessor;
-
- private final ResolvingConversionContext context;
-
- private final Identifier identifier;
-
- private ResolvingRelationalPropertyValueProvider(AggregatePathValueProvider delegate, RowDocumentAccessor accessor,
- ResolvingConversionContext context, Identifier identifier) {
-
- AggregatePath path = context.aggregatePath();
-
- this.delegate = delegate;
- this.accessor = accessor;
- this.context = context;
- this.identifier = path.isEntity()
- ? potentiallyAppendIdentifier(identifier, path.getRequiredLeafEntity(), delegate::getPropertyValue)
- : identifier;
- }
-
- /**
- * Conditionally append the identifier if the entity has an identifier property.
- */
- static Identifier potentiallyAppendIdentifier(Identifier base, RelationalPersistentEntity> entity,
- Function getter) {
-
- if (entity.hasIdProperty()) {
-
- RelationalPersistentProperty idProperty = entity.getRequiredIdProperty();
- Object propertyValue = getter.apply(idProperty);
-
- if (propertyValue != null) {
- return base.withPart(idProperty.getColumnName(), propertyValue, idProperty.getType());
- }
- }
-
- return base;
- }
-
- @SuppressWarnings("unchecked")
- @Nullable
- @Override
- public T getPropertyValue(RelationalPersistentProperty property) {
-
- AggregatePath aggregatePath = this.context.aggregatePath();
-
- if (getConversions().isSimpleType(property.getActualType())) {
- return (T) delegate.getValue(aggregatePath);
- }
-
- if (property.isEntity()) {
-
- if (property.isCollectionLike() || property.isMap()) {
-
- Identifier identifier1 = this.identifier;
- if (property.getOwner().hasIdProperty()) {
- Object id = this.identifier.get(property.getOwner().getRequiredIdProperty().getColumnName());
-
- if (id != null) {
- identifier1 = Identifier.of(aggregatePath.getTableInfo().reverseColumnInfo().name(), id, Object.class);
- }
- }
-
- Iterable