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 6409390088..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,95 +15,50 @@
*/
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.Map;
-import java.util.Optional;
-
-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.relational.core.conversion.MappingRelationalConverter;
import org.springframework.data.relational.core.conversion.RelationalConverter;
-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.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() no-op type factory} throwing {@link UnsupportedOperationException} on type
- * creation. Use
+ * Creates a new {@link BasicJdbcConverter} given {@link MappingContext} and a {@link JdbcTypeFactory#unsupported()
+ * no-op type factory} throwing {@link UnsupportedOperationException} on type creation. Use
* {@link #BasicJdbcConverter(RelationalMappingContext, RelationResolver, CustomConversions, JdbcTypeFactory, IdentifierProcessing)}
* (MappingContext, RelationResolver, JdbcTypeFactory)} to convert arrays and large objects into JDBC-specific types.
*
* @param context must not be {@literal null}.
* @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");
+ public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver) {
+ super(context, relationResolver);
+ }
- this.typeFactory = JdbcTypeFactory.unsupported();
- this.identifierProcessing = IdentifierProcessing.ANSI;
- this.relationResolver = relationResolver;
- this.spELContext = new SpELContext(ResultSetAccessorPropertyAccessor.INSTANCE);
+ /**
+ * Creates a new {@link BasicJdbcConverter} given {@link MappingContext}.
+ *
+ * @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}
+ * @since 3.2
+ */
+ public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
+ CustomConversions conversions, JdbcTypeFactory typeFactory) {
+ super(context, relationResolver, conversions, typeFactory);
}
/**
@@ -115,495 +70,8 @@ public BasicJdbcConverter(
* @param identifierProcessing must not be {@literal null}
* @since 2.0
*/
- 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();
+ public BasicJdbcConverter(RelationalMappingContext context, RelationResolver relationResolver,
+ CustomConversions conversions, JdbcTypeFactory typeFactory, IdentifierProcessing identifierProcessing) {
+ super(context, relationResolver, conversions, typeFactory, identifierProcessing);
}
-
- static Object[] requireObjectArray(Object source) {
-
- Assert.isTrue(source.getClass().isArray(), "Source object is not an array");
-
- Class> componentType = source.getClass().getComponentType();
-
- if (componentType.isPrimitive()) {
- if (componentType == boolean.class) {
- return ArrayUtils.toObject((boolean[]) source);
- }
- if (componentType == byte.class) {
- return ArrayUtils.toObject((byte[]) source);
- }
- if (componentType == char.class) {
- return ArrayUtils.toObject((char[]) source);
- }
- if (componentType == double.class) {
- return ArrayUtils.toObject((double[]) source);
- }
- if (componentType == float.class) {
- return ArrayUtils.toObject((float[]) source);
- }
- if (componentType == int.class) {
- return ArrayUtils.toObject((int[]) source);
- }
- if (componentType == long.class) {
- return ArrayUtils.toObject((long[]) source);
- }
- if (componentType == short.class) {
- return ArrayUtils.toObject((short[]) source);
- }
-
- throw new IllegalArgumentException("Unsupported component type: " + componentType);
- }
- return (Object[]) source;
- }
-
- private class ReadingContext {
-
- private final RelationalPersistentEntity entity;
-
- private final AggregatePath rootPath;
- private final AggregatePath path;
- private final Identifier identifier;
- private final Object key;
-
- private final JdbcPropertyValueProvider propertyValueProvider;
- private final JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider;
- private final ResultSetAccessor accessor;
-
- @SuppressWarnings("unchecked")
- private ReadingContext(AggregatePath rootPath, ResultSetAccessor accessor, Identifier identifier,
- Object key) {
- RelationalPersistentEntity entity = (RelationalPersistentEntity) rootPath.getLeafEntity();
-
- Assert.notNull(entity, "The rootPath must point to an entity");
-
- this.entity = entity;
- this.rootPath = rootPath;
- this.path = getMappingContext().getAggregatePath( this.entity);
- this.identifier = identifier;
- this.key = key;
- this.propertyValueProvider = new JdbcPropertyValueProvider(path, accessor);
- this.backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider(path, accessor);
- this.accessor = accessor;
- }
-
- private ReadingContext(RelationalPersistentEntity entity, AggregatePath rootPath,
- AggregatePath path, Identifier identifier, Object key,
- JdbcPropertyValueProvider propertyValueProvider,
- JdbcBackReferencePropertyValueProvider backReferencePropertyValueProvider, ResultSetAccessor accessor) {
-
- this.entity = entity;
- this.rootPath = rootPath;
- this.path = path;
- this.identifier = identifier;
- this.key = key;
- this.propertyValueProvider = propertyValueProvider;
- this.backReferencePropertyValueProvider = backReferencePropertyValueProvider;
- this.accessor = accessor;
- }
-
- private ReadingContext extendBy(RelationalPersistentProperty property) {
-
- return new ReadingContext<>(
- (RelationalPersistentEntity) getMappingContext().getRequiredPersistentEntity(property.getActualType()),
- rootPath.append(property), path.append(property), identifier, key,
- propertyValueProvider.extendBy(property), backReferencePropertyValueProvider.extendBy(property), accessor);
- }
-
- T mapRow() {
-
- RelationalPersistentProperty idProperty = entity.getIdProperty();
-
- Object idValue = idProperty == null ? null : readFrom(idProperty);
-
- return createInstanceInternal(idValue);
- }
-
- private T populateProperties(T instance, @Nullable Object idValue) {
-
- PersistentPropertyAccessor propertyAccessor = getPropertyAccessor(entity, instance);
- InstanceCreatorMetadata creatorMetadata = entity.getInstanceCreatorMetadata();
-
- entity.doWithAll(property -> {
-
- if (creatorMetadata != null && creatorMetadata.isCreatorParameter(property)) {
- return;
- }
-
- // skip absent simple properties
- if (isSimpleProperty(property)) {
-
- if (!propertyValueProvider.hasProperty(property)) {
- return;
- }
- }
-
- Object value = readOrLoadProperty(idValue, property);
- propertyAccessor.setProperty(property, value);
- });
-
- return propertyAccessor.getBean();
- }
-
- @Nullable
- private Object readOrLoadProperty(@Nullable Object id, RelationalPersistentProperty property) {
-
- if ((property.isCollectionLike() && property.isEntity()) || property.isMap()) {
-
- Iterable