I am struggling to get my PhysicalNamingStrategy
Implementation in a Spring Boot + Hibernate Project to work as expected. The problem is that both, @Value
and @Autowired
annotated variables are always null / not properly injected with values from my application.properties
. I need this in order to be able to externalize parameters like schema and table names and i can't use the fixed variant like this:
@Entity
@Table(name = "table_name", schema = "primary_schema")
Well actually I do, but the PhysicalNamingStrategy
comes in and "translates" the static names to the parameterized names. At least that is what should happen.
I am 3/4 sure, that Spring is aware of my Class (Package and Class is scanned / found via ComponentScan) because when I create duplicates I get an expected Exception during bootup telling me that Spring found 2 identical beans. So I have no clue why the variables are not injected properly in this Class. Other classes (in the same and in other packages!) work fine with @Value
and @Autowired
annotations.
My project structure looks like this (reduced to the relevant parts):
project/src/main/java/
----------------------org.packagename
-------------------------configuration
-----------------------------BeanConfig.java
-----------------------------DataSourceConfiguration.java
-----------------------------PhysicalNamingStrategyImpl.java
-------------------------constant
-------------------------controller
-------------------------exception
-------------------------model
-------------------------repository
-------------------------scheduler
-------------------------service
-------------------------AppMainClass.java
project/src/main/resources
----------------------application.properties
----------------------application-devel.properties
----------------------application-prod.properties
----------------------schema-h2.sql
----------------------log4j2.xml
I am using:
- spring-boot-2.3.2 (multiple dependencies like spring-boot-autoconfigure, etc.)
- spring-5.2.8 (multiple dependencies like spring-beans, etc.
- hibernate-5.4.18
I configured Spring to use that Naming Strategy Implementation in the application.properties
using this parameter:
spring.jpa.properties.hibernate.physical_naming_strategy=org.packagename.configuration.PhysicalNamingStrategyImpl
The Class is definitly used because i see the expected Log-Outputs as well as reach my breakpoints in the methods of the Class. So up until here everything is working as it should.
But the @Value
annotated variables are always null while in other Classes the same values have the expected values from the properties file.
Here is the (test) class in Question (added those manual variable initialization after the //FIXME
Comments in order to make it work at all, this will be removed as soon as the injection is working):
package org.packagename.configuration;
import java.io.Serializable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* //stripped
*/
@Component
public class PhysicalNamingStrategyImpl implements PhysicalNamingStrategy, Serializable {
//public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {
/** */
private static final long serialVersionUID = 2389476641866177676L;
// public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();
private Logger logger = LogManager.getLogger(PhysicalNamingStrategyImpl.class);
@Value("${app.primary.schema.name}")
private String primarySchemaName;
@Value("${app.primary.table.name}")
private String primaryTableName;
@Value("${app.secondary.schema.name}")
private String secondarySchemaName;
@Value("${app.secondary.table.name}")
private String secondaryTableName;
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {
logger.debug("toPhysicalSchemaName: {} with primarySchemaName: {}, secondarySchemaName: {}", name, primarySchemaName, secondarySchemaName);
if (name == null) {
return null;
}
// FIXME @Value always null....
primarySchemaName = "ACTUAL_SCHEMA_NAME";
secondarySchemaName = "ACTUAL_SCHEMA_NAME2";
switch (name.getText()) {
case "primary_schema":
return new Identifier(primarySchemaName, name.isQuoted());
case "secondary_schema":
return new Identifier(secondarySchemaName, name.isQuoted());
default:
return name;
}
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
logger.debug("toPhysicalTableName: {} with primaryTableName : {}, secondaryTableName : {}", name, primaryTableName , secondaryTableName );
if (name == null) {
return null;
}
// FIXME @Value always null....
primaryTableName = "ACTUAL_TABLE_NAME";
secondaryTableName = "ACTUAL_TABLE_NAME2";
switch (name.getText()) {
case "table_name":
return new Identifier(syncLogTableTableName, name.isQuoted());
case "table_name2":
return new Identifier(assetExportDataTableName, name.isQuoted());
default:
return name;
}
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) {
return name;
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) {
return name;
}
}
I am not instantiating this Class manually (no new PhysicalNamingStrategyImpl()
) in the Code of my project so it should be handled completly by Spring itself. But I am not sure how, where and when does Spring create this Class during boot.