Skip to content

Commit 152bf52

Browse files
committed
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.
1 parent 4fd31c6 commit 152bf52

18 files changed

+607
-29
lines changed

src/main/java/org/springframework/data/jdbc/mapping/model/BasicJdbcPersistentProperty.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ protected Association<JdbcPersistentProperty> createAssociation() {
7474
* @see org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty#getColumnName()
7575
*/
7676
public String getColumnName() {
77-
return getName();
77+
return this.context.getNamingStrategy().getColumnName(this);
7878
}
7979

8080
/**
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jdbc.mapping.model;
17+
18+
/**
19+
* Token definition of context.
20+
*
21+
* @author Greg Turnquist
22+
*/
23+
public interface Context {
24+
25+
String getContext();
26+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jdbc.mapping.model;
17+
18+
/**
19+
* Basic implementation of {@link NamingStrategy} with no schema, table based on {@link Class} and
20+
* column name based on {@link JdbcPersistentProperty}.
21+
*
22+
* NOTE: Can also be used as an adapter. Create an anonymous subclass and override any settings to implement
23+
* a different strategy on the fly.
24+
*
25+
* @author Greg Turnquist
26+
*/
27+
public class DefaultNamingStrategy implements NamingStrategy {
28+
29+
/**
30+
* No schema at all!
31+
*
32+
* @return
33+
*/
34+
@Override
35+
public String getSchema() {
36+
return "";
37+
}
38+
39+
/**
40+
* Look up the {@link Class}'s simple name.
41+
*
42+
* @param type
43+
* @return
44+
*/
45+
@Override
46+
public String getTableName(Class<?> type) {
47+
return type.getSimpleName();
48+
}
49+
50+
51+
/**
52+
* Look up the {@link JdbcPersistentProperty}'s name.
53+
*
54+
* @param property
55+
* @return
56+
*/
57+
@Override
58+
public String getColumnName(JdbcPersistentProperty property) {
59+
return property.getName();
60+
}
61+
}

src/main/java/org/springframework/data/jdbc/mapping/model/JdbcMappingContext.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
import static java.util.Arrays.*;
1919

20+
import lombok.Getter;
21+
import lombok.experimental.Wither;
22+
2023
import java.math.BigDecimal;
2124
import java.math.BigInteger;
2225
import java.time.temporal.Temporal;
@@ -46,7 +49,11 @@ public class JdbcMappingContext extends AbstractMappingContext<JdbcPersistentEnt
4649
Temporal.class //
4750
));
4851

49-
public JdbcMappingContext() {
52+
private final @Getter @Wither NamingStrategy namingStrategy;
53+
54+
public JdbcMappingContext(NamingStrategy namingStrategy) {
55+
56+
this.namingStrategy = namingStrategy;
5057
setSimpleTypeHolder(new SimpleTypeHolder(CUSTOM_SIMPLE_TYPES, true));
5158
}
5259

@@ -80,7 +87,7 @@ public List<PropertyPath> referencedEntities(Class<?> rootType, PropertyPath pat
8087
*/
8188
@Override
8289
protected <T> JdbcPersistentEntity<T> createPersistentEntity(TypeInformation<T> typeInformation) {
83-
return new JdbcPersistentEntityImpl<>(typeInformation);
90+
return new JdbcPersistentEntityImpl<>(typeInformation, this.namingStrategy);
8491
}
8592

8693
/*

src/main/java/org/springframework/data/jdbc/mapping/model/JdbcPersistentEntityImpl.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,19 @@
2929
class JdbcPersistentEntityImpl<T> extends BasicPersistentEntity<T, JdbcPersistentProperty>
3030
implements JdbcPersistentEntity<T> {
3131

32+
private final NamingStrategy namingStrategy;
3233
private final @Getter String tableName;
3334

3435
/**
3536
* Creates a new {@link JdbcPersistentEntityImpl} for the given {@link TypeInformation}.
3637
*
3738
* @param information must not be {@literal null}.
3839
*/
39-
JdbcPersistentEntityImpl(TypeInformation<T> information) {
40+
JdbcPersistentEntityImpl(TypeInformation<T> information, NamingStrategy namingStrategy) {
4041

4142
super(information);
42-
43-
tableName = getType().getSimpleName();
43+
this.namingStrategy = namingStrategy;
44+
this.tableName = this.namingStrategy.getSchema() + this.namingStrategy.getTableName(getType());
4445
}
4546

4647
/*
@@ -49,7 +50,7 @@ class JdbcPersistentEntityImpl<T> extends BasicPersistentEntity<T, JdbcPersisten
4950
*/
5051
@Override
5152
public String getIdColumn() {
52-
return getRequiredIdProperty().getName();
53+
return this.namingStrategy.getColumnName(getRequiredIdProperty());
5354
}
5455

5556
@Override
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jdbc.mapping.model;
17+
18+
/**
19+
* @author Greg Turnquist
20+
*/
21+
public interface NamingStrategy {
22+
23+
String getSchema();
24+
25+
String getTableName(Class<?> type);
26+
27+
String getColumnName(JdbcPersistentProperty property);
28+
29+
}

src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@
1515
*/
1616
package org.springframework.data.jdbc.repository.support;
1717

18-
import lombok.RequiredArgsConstructor;
19-
2018
import org.springframework.context.ApplicationEventPublisher;
2119
import org.springframework.data.jdbc.core.JdbcEntityTemplate;
2220
import org.springframework.data.jdbc.mapping.model.BasicJdbcPersistentEntityInformation;
2321
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
2422
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
2523
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntityInformation;
24+
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
2625
import org.springframework.data.jdbc.repository.SimpleJdbcRepository;
2726
import org.springframework.data.repository.core.EntityInformation;
2827
import org.springframework.data.repository.core.RepositoryInformation;
@@ -34,13 +33,19 @@
3433
* @author Jens Schauder
3534
* @since 2.0
3635
*/
37-
@RequiredArgsConstructor
3836
public class JdbcRepositoryFactory extends RepositoryFactorySupport {
3937

40-
private final JdbcMappingContext context = new JdbcMappingContext();
38+
private final JdbcMappingContext context;
4139
private final NamedParameterJdbcOperations jdbcOperations;
4240
private final ApplicationEventPublisher publisher;
4341

42+
public JdbcRepositoryFactory(NamedParameterJdbcOperations namedParameterJdbcOperations, ApplicationEventPublisher publisher, NamingStrategy namingStrategy) {
43+
44+
this.jdbcOperations = namedParameterJdbcOperations;
45+
this.publisher = publisher;
46+
this.context = new JdbcMappingContext(namingStrategy);
47+
}
48+
4449
@SuppressWarnings("unchecked")
4550
@Override
4651
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) {

src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
import org.springframework.context.ApplicationContext;
2525
import org.springframework.context.ApplicationEventPublisher;
26+
import org.springframework.data.jdbc.mapping.model.DefaultNamingStrategy;
27+
import org.springframework.data.jdbc.mapping.model.NamingStrategy;
2628
import org.springframework.data.repository.Repository;
2729
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
2830
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
@@ -45,9 +47,12 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
4547
"No unique NamedParameterJdbcOperation could be found, " //
4648
+ "nor JdbcOperations or DataSource to construct one from.";
4749

50+
private static final String NO_NAMING_STRATEGY_ERROR_MESSAGE = "No unique NamingStrategy could be found.";
51+
4852
private static final String NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME = "namedParameterJdbcTemplate";
4953
private static final String JDBC_OPERATIONS_BEAN_NAME = "jdbcTemplate";
5054
private static final String DATA_SOURCE_BEAN_NAME = "dataSource";
55+
private static final String NAMING_STRATEGY_BEAN_NAME = "namingStrategy";
5156

5257
private final ApplicationEventPublisher applicationEventPublisher;
5358
private final ApplicationContext context;
@@ -62,7 +67,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
6267

6368
@Override
6469
protected RepositoryFactorySupport doCreateRepositoryFactory() {
65-
return new JdbcRepositoryFactory(findOrCreateJdbcOperations(), applicationEventPublisher);
70+
return new JdbcRepositoryFactory(findOrCreateJdbcOperations(), applicationEventPublisher, findOrCreateNamingStrategy());
6671
}
6772

6873
private NamedParameterJdbcOperations findOrCreateJdbcOperations() {
@@ -75,6 +80,12 @@ private NamedParameterJdbcOperations findOrCreateJdbcOperations() {
7580
.orElseThrow(() -> new IllegalStateException(NO_NAMED_PARAMETER_JDBC_OPERATION_ERROR_MESSAGE));
7681
}
7782

83+
private NamingStrategy findOrCreateNamingStrategy() {
84+
85+
return getNamingStrategy()
86+
.orElse(new DefaultNamingStrategy());
87+
}
88+
7889
private Optional<NamedParameterJdbcOperations> getNamedParameterJdbcOperations() {
7990
return getBean(NamedParameterJdbcOperations.class, NAMED_PARAMETER_JDBC_OPERATIONS_BEAN_NAME);
8091
}
@@ -87,6 +98,10 @@ private Optional<DataSource> getDataSource() {
8798
return getBean(DataSource.class, DATA_SOURCE_BEAN_NAME);
8899
}
89100

101+
private Optional<NamingStrategy> getNamingStrategy() {
102+
return getBean(NamingStrategy.class, NAMING_STRATEGY_BEAN_NAME);
103+
}
104+
90105
private <R> Optional<R> getBean(Class<R> type, String name) {
91106

92107
Map<String, R> beansOfType = context.getBeansOfType(type);

0 commit comments

Comments
 (0)