2

Something similar to this question but OP there not mentioned that whether they creating LocalContainerEntityManagerFactoryBean .
Spring not injecting @Value or @Autowired annotated variables in PhysicalNamingStrategy Implementations:

@Configuration
public class SchemaPhysicalNamingStrategy extends CamelCaseToUnderscoresNamingStrategy {

    @Value(value = "${spring.jpa.hibernate.default_schema}")
    private String schemaName;

    @Value(value = "${spring.jpa.hibernate.default_catalog}")
    private String catalogName;

    /**
     * @param identifier
     * @param jdbcEnvironment
     * @return
     */
    @Override
    public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnvironment) {
        if (isNull(identifier)) {
            identifier = toIdentifier(this.schemaName);
        }
        return super.toPhysicalSchemaName(identifier, jdbcEnvironment);
    }

    @Override
    public Identifier toPhysicalCatalogName(
            Identifier identifier, JdbcEnvironment jdbcEnvironment) {
        if (isNull(identifier)) {
            identifier = toIdentifier(this.catalogName);
        }
        return super.toPhysicalCatalogName(identifier, jdbcEnvironment);
    }
}

Below is one of the two LocalContainerEntityManagerFactoryBean objects which needs customised physical naming strategy.

@Bean(name = "integrationEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean integrationEntityManagerFactory(
        EntityManagerFactoryBuilder builder) {
    return builder.dataSource(integrationDataSource())
            .packages("xx.xx.xx.xxxx.entity")
            .properties(jpaProperties())
            .build();
}


    protected Map<String, Object> jpaProperties() {
        return of(
                "hibernate.physical_naming_strategy", SchemaPhysicalNamingStrategy.class.getName());
    }

Issue is - @Value and @Autowired are not working on SchemaPhysicalNamingStrategy as spring creates instance using reflection. Can't add it to constructor as spring calls constructor without params using reflection. One option is to create SessionFactory bean and set on it but that will be overkill. Please help.

Sammy Pawar
  • 1,201
  • 3
  • 19
  • 38
  • For spring to make use of the Value and Autowired annotation, the class should be annotated with Component so that it can be picked up during context initialization. Have you tried creating a spring Bean from the SchemaPhysicalNamingStrategy ? – SputNick Jan 27 '23 at 12:37
  • @NikhilJoseph, yes. My SchemaPhysicalNamingStrategy has Compoent annotation, but it doesn't help. Its instance is created by Spring using reflection. HibernateJpaConfiguration.java this.hibernatePropertiesCustomizers = determineHibernatePropertiesCustomizers( physicalNamingStrategy.getIfAvailable(), implicitNamingStrategy.getIfAvailable(), beanFactory, hibernatePropertiesCustomizers.orderedStream().collect(Collectors.toList())); – Sammy Pawar Jan 27 '23 at 16:30
  • What are you trying to accomplish? Why are you trying to inject `schema` and `catalogName` into a naming strategy? Can you add the values to the Map in `jpaProperties()`? – Bernie Jan 30 '23 at 06:59
  • 1
    I don't think that Spring is the issue here. `hibernate.physical_naming_strategy` is vendor-specific (Hibernate), and it's unlikely that Spring is involved in the construction of the object. – Bernie Jan 30 '23 at 07:21
  • @Bernie. Thanks. I just want to dynamically set schema, catalog names in physical naming strategy instance instead of hard coding in java code. I am not sure how I can set schema and catalog names in jpaProperties - protected Map jpaProperties() { return of( "hibernate.physical_naming_strategy", SchemaPhysicalNamingStrategy.class.getName()); } – Sammy Pawar Jan 30 '23 at 17:12
  • @Bernie, Thanks. see HibernateJpaConfiguration.java, if LocalContainerEntityManagerFactoryBean bean is present then spring won't touch vendor properties. Because of "ConditionalOnMissingBean". Bean Primary ConditionalOnMissingBean({ LocalContainerEntityManagerFactoryBean.class, EntityManagerFactory.class }) public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) { Map vendorProperties = getVendorProperties(); customizeVendorProperties(vendorProperties); – Sammy Pawar Jan 30 '23 at 17:18

1 Answers1

2

Documentation says following:

Hibernate supports using the following integrations as managed beans:

  • jakarta.persistence.AttributeConverter
  • Jakarta Persistence "entity listener" classes
  • org.hibernate.type.descriptor.jdbc.JdbcType
  • org.hibernate.type.descriptor.java.BasicJavaType
  • org.hibernate.type.descriptor.java.MutabilityPlan
  • org.hibernate.usertype.UserType
  • org.hibernate.usertype.UserCollectionType
  • org.hibernate.metamodel.EmbeddableInstantiator
  • org.hibernate.envers.RevisionListener
  • org.hibernate.id.IdentifierGenerator

Since Hibernate do not recognise naming strategies as managed beans you need to pass them as instances to property map, for example:

@Bean(name = "integrationEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean integrationEntityManagerFactory(
        EntityManagerFactoryBuilder builder
        SchemaPhysicalNamingStrategy namingStrategy) {
    return builder.dataSource(integrationDataSource())
            .packages("xx.xx.xx.xxxx.entity")
            .properties(jpaProperties(namingStrategy))
            .build();
}


protected Map<String, Object> jpaProperties(PhysicalNamingStrategy namingStrategy) {
    return of("hibernate.physical_naming_strategy", namingStrategy);
}
Andrey B. Panfilov
  • 4,324
  • 2
  • 12
  • 18
  • Nice..works like a charm. I didn't know you can pass instance of PhysicalNamingStrategy instead of name. Thanks a lot. I will share bounty when it allows me tomorrow morning. – Sammy Pawar Jan 30 '23 at 20:46
  • it save my day . thanks alot @Andrey B. Pandilov for this amzing and nice solution – Noshaf Mar 14 '23 at 08:12
  • @Noshaf the A was given for particular Q (why specifying class name does not work), in your case I do believe that is enough to define `@Component` implementing `PhysicalNamingStrategy` and `spring-boot` will do it's magic in [`HibernateJpaConfiguration`](https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.java#L216) – Andrey B. Panfilov Mar 14 '23 at 09:23