DATAJDBC-107 - Implement naming strategy.

Created NamingStrategy and a default implementation that replicates the current solution. Several unit tests illustrates how to override the default and plugin a custom solution including a ThreadLocal, contextual one that could be user-based if, for example, Spring Security's SecurityContextHolder was used.
This commit is contained in:
Greg Turnquist
2017-08-07 17:10:18 -05:00
committed by Jens Schauder
parent 96e3b2c681
commit f7bff01d3e
17 changed files with 595 additions and 29 deletions

View File

@@ -74,7 +74,7 @@ public class BasicJdbcPersistentProperty extends AnnotationBasedPersistentProper
* @see org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty#getColumnName()
*/
public String getColumnName() {
return getName();
return this.context.getNamingStrategy().getColumnName(this);
}
/**

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2017 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
*
* http://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.mapping.model;
/**
* Basic implementation of {@link NamingStrategy} with no schema, table based on {@link Class} and
* column name based on {@link JdbcPersistentProperty}.
*
* NOTE: Can also be used as an adapter. Create an anonymous subclass and override any settings to implement
* a different strategy on the fly.
*
* @author Greg Turnquist
*/
public class DefaultNamingStrategy implements NamingStrategy {
/**
* No schema at all!
*/
@Override
public String getSchema() {
return "";
}
/**
* Look up the {@link Class}'s simple name.
*/
@Override
public String getTableName(Class<?> type) {
return type.getSimpleName();
}
/**
* Look up the {@link JdbcPersistentProperty}'s name.
*/
@Override
public String getColumnName(JdbcPersistentProperty property) {
return property.getName();
}
}

View File

@@ -17,6 +17,8 @@ package org.springframework.data.jdbc.mapping.model;
import static java.util.Arrays.*;
import lombok.Getter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.temporal.Temporal;
@@ -46,7 +48,11 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
Temporal.class //
));
public JdbcMappingContext() {
private final @Getter NamingStrategy namingStrategy;
public JdbcMappingContext(NamingStrategy namingStrategy) {
this.namingStrategy = namingStrategy;
setSimpleTypeHolder(new SimpleTypeHolder(CUSTOM_SIMPLE_TYPES, true));
}
@@ -80,7 +86,7 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
*/
@Override
protected <T> JdbcPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
return new JdbcPersistentEntityImpl<>(typeInformation);
return new JdbcPersistentEntityImpl<>(typeInformation, this.namingStrategy);
}
/*

View File

@@ -29,6 +29,7 @@ import org.springframework.data.util.TypeInformation;
class JdbcPersistentEntityImpl<T> extends BasicPersistentEntity<T, JdbcPersistentProperty>
implements JdbcPersistentEntity<T> {
private final NamingStrategy namingStrategy;
private final @Getter String tableName;
/**
@@ -36,11 +37,12 @@ class JdbcPersistentEntityImpl<T> extends BasicPersistentEntity<T, JdbcPersisten
*
* @param information must not be {@literal null}.
*/
JdbcPersistentEntityImpl(TypeInformation<T> information) {
JdbcPersistentEntityImpl(TypeInformation<T> information, NamingStrategy namingStrategy) {
super(information);
tableName = getType().getSimpleName();
this.namingStrategy = namingStrategy;
this.tableName = this.namingStrategy.getQualifiedTableName(getType());
}
/*
@@ -49,7 +51,7 @@ class JdbcPersistentEntityImpl<T> extends BasicPersistentEntity<T, JdbcPersisten
*/
@Override
public String getIdColumn() {
return getRequiredIdProperty().getName();
return this.namingStrategy.getColumnName(getRequiredIdProperty());
}
@Override

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2017 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
*
* http://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.mapping.model;
/**
* @author Greg Turnquist
*/
public interface NamingStrategy {
String getSchema();
String getTableName(Class<?> type);
String getColumnName(JdbcPersistentProperty property);
default String getQualifiedTableName(Class<?> type) {
return this.getSchema() + (this.getSchema().equals("") ? "" : ".") + this.getTableName(type);
}
}

View File

@@ -15,14 +15,13 @@
*/
package org.springframework.data.jdbc.repository.support;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jdbc.core.JdbcEntityTemplate;
import org.springframework.data.jdbc.mapping.model.BasicJdbcPersistentEntityInformation;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityInformation;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.jdbc.repository.SimpleJdbcRepository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.RepositoryInformation;
@@ -34,13 +33,19 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
* @author Jens Schauder
* @since 2.0
*/
@RequiredArgsConstructor
public class JdbcRepositoryFactory extends RepositoryFactorySupport {
private final JdbcMappingContext context = new JdbcMappingContext();
private final JdbcMappingContext context;
private final NamedParameterJdbcOperations jdbcOperations;
private final ApplicationEventPublisher publisher;
public JdbcRepositoryFactory(NamedParameterJdbcOperations namedParameterJdbcOperations, ApplicationEventPublisher publisher, NamingStrategy namingStrategy) {
this.jdbcOperations = namedParameterJdbcOperations;
this.publisher = publisher;
this.context = new JdbcMappingContext(namingStrategy);
}
@SuppressWarnings("unchecked")
@Override
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) {

View File

@@ -23,6 +23,8 @@ import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
@@ -45,9 +47,12 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
"No unique NamedParameterJdbcOperation could be found, " //
+ "nor JdbcOperations or DataSource to construct one from.";
private static final String NO_NAMING_STRATEGY_ERROR_MESSAGE = "No unique NamingStrategy could be found.";
private static final String NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME = "namedParameterJdbcTemplate";
private static final String JDBC_OPERATIONS_BEAN_NAME = "jdbcTemplate";
private static final String DATA_SOURCE_BEAN_NAME = "dataSource";
private static final String NAMING_STRATEGY_BEAN_NAME = "namingStrategy";
private final ApplicationEventPublisher applicationEventPublisher;
private final ApplicationContext context;
@@ -62,7 +67,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
@Override
protected RepositoryFactorySupport doCreateRepositoryFactory() {
return new JdbcRepositoryFactory(findOrCreateJdbcOperations(), applicationEventPublisher);
return new JdbcRepositoryFactory(findOrCreateJdbcOperations(), applicationEventPublisher, findOrCreateNamingStrategy());
}
private NamedParameterJdbcOperations findOrCreateJdbcOperations() {
@@ -75,6 +80,12 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
.orElseThrow(() -> new IllegalStateException(NO_NAMED_PARAMETER_JDBC_OPERATION_ERROR_MESSAGE));
}
private NamingStrategy findOrCreateNamingStrategy() {
return getNamingStrategy()
.orElse(new DefaultNamingStrategy());
}
private Optional<NamedParameterJdbcOperations> getNamedParameterJdbcOperations() {
return getBean(NamedParameterJdbcOperations.class, NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME);
}
@@ -87,6 +98,10 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
return getBean(DataSource.class, DATA_SOURCE_BEAN_NAME);
}
private Optional<NamingStrategy> getNamingStrategy() {
return getBean(NamingStrategy.class, NAMING_STRATEGY_BEAN_NAME);
}
private <R> Optional<R> getBean(Class<R> type, String name) {
Map<String, R> beansOfType = context.getBeansOfType(type);