I have an app that uses spring boot 2.7.9 and Spring data jpa 2.7.8.
It has a multitenant Oracle UCP data source, with other complexities like some of the repos are JPA based and other JDBC based hence JPA has been configured like so:
Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder,
TenantRoutingDataSource tenantRoutingDataSource) {
return builder.dataSource(tenantRoutingDataSource)
.packages("com.orders", "com.orders.migration")
.build();
}
@Bean(name = "transactionManager")
public JpaTransactionManager transactionManager(
@Autowired @Qualifier("entityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
return new JpaTransactionManager(entityManagerFactoryBean.getObject());
}
I have a naming strategy class that looks like this :
@AllArgsConstructor
@NoArgsConstructor
@Component
public class AppIdNamingStrategy extends CamelCaseToUnderscoresNamingStrategy {
private BatchProperties batchProperties;
@Override
public Identifier toPhysicalTableName(final Identifier name, final JdbcEnvironment jdbcEnvironment) {
return this.customize(name, jdbcEnvironment);
}
@Override
public Identifier toPhysicalSequenceName(final Identifier name, final JdbcEnvironment jdbcEnvironment) {
return this.customize(name, jdbcEnvironment);
}
private Identifier customize(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name == null) {
return null;
} else {
StringBuilder builder = new StringBuilder(name.getText().replace('.', '_'));
for(int i = 1; i < builder.length() - 1; ++i) {
if (this.isUnderscoreRequiredCustom(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
builder.insert(i++, '_');
}
}
if(isCustomOrderIdentifier(name)) {
builder.insert(0, batchProperties.getJdbc().getTablePrefix());
}
return this.getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
}
}
private boolean isCustomOrderIdentifier(final Identifier name) {
return "custom_order".equalsIgnoreCase(name.getText()));
}
private boolean isUnderscoreRequiredCustom(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
}
@Autowired
public void setBatchProperties(final BatchProperties batchProperties) {
this.batchProperties = batchProperties;
}
}
BatchProperties
is a service that provides the configurable table prefix from the application.yml
which has to be applied to some table names when the application starts.
I configured the above class using the following JPA property however its not picked up :
spring.jpa.hibernate.naming.physical-strategy
Since the above is not working I tried the following :
spring.jpa.properties.hibernate.physical_naming_strategy
The class gets picked up however it seems that hibernate creates its own object instead of using the bean that I created because which the BatchProperties service in the AppIdNamingStrategy is not set.
So I am kind of stuck. How do I programmatically introduce my own naming strategy service ?
Is there a way to get a handle of the naming strategy created by hibernate when using the spring.jpa.properties.hibernate.physical_naming_strategy
?
EDIT: Found this thread: Can't set JPA naming strategy after configuring multiple data sources (Spring 1.4.1 / Hibernate 5.x)
It seems that if one uses multiple data sources spring.jpa.hibernate.naming.physical-strategy
is not picked up at all.