9 changed files with 203 additions and 92 deletions
@ -0,0 +1,168 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2025 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. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.data.jdbc.repository.config; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.jspecify.annotations.Nullable; |
||||||
|
|
||||||
|
import org.springframework.core.convert.converter.Converter; |
||||||
|
import org.springframework.data.convert.CustomConversions; |
||||||
|
import org.springframework.data.jdbc.core.JdbcAggregateOperations; |
||||||
|
import org.springframework.data.jdbc.core.convert.DataAccessStrategy; |
||||||
|
import org.springframework.data.jdbc.core.convert.DataAccessStrategyFactory; |
||||||
|
import org.springframework.data.jdbc.core.convert.DefaultJdbcTypeFactory; |
||||||
|
import org.springframework.data.jdbc.core.convert.JdbcConverter; |
||||||
|
import org.springframework.data.jdbc.core.convert.JdbcCustomConversions; |
||||||
|
import org.springframework.data.jdbc.core.convert.MappingJdbcConverter; |
||||||
|
import org.springframework.data.jdbc.core.convert.QueryMappingConfiguration; |
||||||
|
import org.springframework.data.jdbc.core.convert.RelationResolver; |
||||||
|
import org.springframework.data.jdbc.core.dialect.JdbcArrayColumns; |
||||||
|
import org.springframework.data.jdbc.core.dialect.JdbcDialect; |
||||||
|
import org.springframework.data.jdbc.core.mapping.JdbcMappingContext; |
||||||
|
import org.springframework.data.jdbc.core.mapping.JdbcSimpleTypes; |
||||||
|
import org.springframework.data.mapping.model.SimpleTypeHolder; |
||||||
|
import org.springframework.data.relational.RelationalManagedTypes; |
||||||
|
import org.springframework.data.relational.core.dialect.Dialect; |
||||||
|
import org.springframework.data.relational.core.mapping.DefaultNamingStrategy; |
||||||
|
import org.springframework.data.relational.core.mapping.NamingStrategy; |
||||||
|
import org.springframework.data.relational.core.mapping.Table; |
||||||
|
import org.springframework.data.util.TypeScanner; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* Utility class to providing factory methods for JDBC infrastructure components. |
||||||
|
* <p> |
||||||
|
* Mainly for use within the framework or for configuration arrangements that require customization of configuration. |
||||||
|
* |
||||||
|
* @author Mark Paluch |
||||||
|
* @since 4.0 |
||||||
|
*/ |
||||||
|
public final class JdbcConfiguration { |
||||||
|
|
||||||
|
private JdbcConfiguration() {} |
||||||
|
|
||||||
|
/** |
||||||
|
* Register custom {@link Converter}s in a {@link JdbcCustomConversions} object if required. |
||||||
|
* |
||||||
|
* @param dialect the JDBC dialect in use. |
||||||
|
* @param userConverters list of user converters, must not be {@literal null}. |
||||||
|
* @return will never be {@literal null}. |
||||||
|
*/ |
||||||
|
public static JdbcCustomConversions createCustomConversions(JdbcDialect dialect, List<?> userConverters) { |
||||||
|
|
||||||
|
SimpleTypeHolder simpleTypeHolder = new SimpleTypeHolder(dialect.simpleTypes(), JdbcSimpleTypes.HOLDER); |
||||||
|
|
||||||
|
return new JdbcCustomConversions(CustomConversions.StoreConversions.of(simpleTypeHolder, storeConverters(dialect)), |
||||||
|
userConverters); |
||||||
|
} |
||||||
|
|
||||||
|
private static List<Object> storeConverters(Dialect dialect) { |
||||||
|
|
||||||
|
List<Object> converters = new ArrayList<>(); |
||||||
|
converters.addAll(dialect.getConverters()); |
||||||
|
converters.addAll(JdbcCustomConversions.storeConverters()); |
||||||
|
return converters; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Register a {@link JdbcMappingContext} and apply an optional {@link NamingStrategy}. |
||||||
|
* |
||||||
|
* @param jdbcManagedTypes JDBC managed types. |
||||||
|
* @param customConversions the custom conversions. |
||||||
|
* @param namingStrategy optional {@link NamingStrategy}. Use {@link DefaultNamingStrategy#INSTANCE} as fallback. |
||||||
|
* @return must not be {@literal null}. |
||||||
|
*/ |
||||||
|
public static JdbcMappingContext createMappingContext(RelationalManagedTypes jdbcManagedTypes, |
||||||
|
JdbcCustomConversions customConversions, @Nullable NamingStrategy namingStrategy) { |
||||||
|
|
||||||
|
JdbcMappingContext mappingContext = JdbcMappingContext |
||||||
|
.forQuotedIdentifiers(namingStrategy != null ? namingStrategy : DefaultNamingStrategy.INSTANCE); |
||||||
|
mappingContext.setSimpleTypeHolder(customConversions.getSimpleTypeHolder()); |
||||||
|
mappingContext.setManagedTypes(jdbcManagedTypes); |
||||||
|
|
||||||
|
return mappingContext; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a {@link JdbcConverter}. |
||||||
|
* |
||||||
|
* @param mappingContext must not be {@literal null}. |
||||||
|
* @param operations must not be {@literal null}. |
||||||
|
* @param relationResolver must not be {@literal null}. |
||||||
|
* @param conversions must not be {@literal null}. |
||||||
|
* @param dialect the JDBC dialect in use. |
||||||
|
* @return must not be {@literal null}. |
||||||
|
*/ |
||||||
|
public static JdbcConverter createConverter(JdbcMappingContext mappingContext, |
||||||
|
NamedParameterJdbcOperations operations, RelationResolver relationResolver, JdbcCustomConversions conversions, |
||||||
|
JdbcDialect dialect) { |
||||||
|
|
||||||
|
JdbcArrayColumns arrayColumns = JdbcDialect.getArraySupport(dialect); |
||||||
|
DefaultJdbcTypeFactory jdbcTypeFactory = new DefaultJdbcTypeFactory(operations.getJdbcOperations(), arrayColumns); |
||||||
|
|
||||||
|
MappingJdbcConverter mappingJdbcConverter = new MappingJdbcConverter(mappingContext, relationResolver, conversions, |
||||||
|
jdbcTypeFactory); |
||||||
|
|
||||||
|
if (operations.getJdbcOperations() instanceof JdbcTemplate jdbcTemplate) { |
||||||
|
mappingJdbcConverter.setExceptionTranslator(jdbcTemplate.getExceptionTranslator()); |
||||||
|
} |
||||||
|
|
||||||
|
return mappingJdbcConverter; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a {@link DataAccessStrategy} for reuse in the {@link JdbcAggregateOperations} and the {@link JdbcConverter}. |
||||||
|
* Override this method to register a bean of type {@link DataAccessStrategy} if your use case requires a more |
||||||
|
* specialized {@link DataAccessStrategy}. |
||||||
|
* |
||||||
|
* @param operations must not be {@literal null}. |
||||||
|
* @param jdbcConverter must not be {@literal null}. |
||||||
|
* @param mappingConfiguration mapping configuration, can be {@literal null}. |
||||||
|
* @param dialect the JDBC dialect in use. |
||||||
|
* @return will never be {@literal null}. |
||||||
|
*/ |
||||||
|
public static DataAccessStrategy createDataAccessStrategy(NamedParameterJdbcOperations operations, |
||||||
|
JdbcConverter jdbcConverter, @Nullable QueryMappingConfiguration mappingConfiguration, JdbcDialect dialect) { |
||||||
|
return new DataAccessStrategyFactory(jdbcConverter, operations, dialect, |
||||||
|
mappingConfiguration == null ? QueryMappingConfiguration.EMPTY : mappingConfiguration).create(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Scans the given base package for entities, i.e. JDBC-specific types annotated with {@link Table}. |
||||||
|
* |
||||||
|
* @param basePackage must not be {@literal null}. |
||||||
|
* @return a set of classes identified as entities. |
||||||
|
*/ |
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public static Set<Class<?>> scanForEntities(String basePackage) { |
||||||
|
|
||||||
|
if (!StringUtils.hasText(basePackage)) { |
||||||
|
return Collections.emptySet(); |
||||||
|
} |
||||||
|
|
||||||
|
return TypeScanner.typeScanner(JdbcConfiguration.class.getClassLoader()) //
|
||||||
|
.forTypesAnnotatedWith(Table.class) //
|
||||||
|
.scanPackages(basePackage) //
|
||||||
|
.collectAsSet(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue