Christof Schulz
Christof Schulz

Reputation: 11

Loading spring property before hibernate initialization

In my JPA-Springboot-app I have to support different databases, i.e. postgres and oracle. I have an entity with a lob type and i want to store the data as string. Because postgres stores lobs differently to other databases, I tried to choose the sql type dependent on the database dialect, according to these instruction: https://geeknet.me/hibernate-postgresql-the-lob-annotation/

So here is what i have:

@Entity
public class MyEntity {

    @EmbeddedId
    private MyPk myPk;

    @Lob
    @Column(name = "value", nullable = false)
    @Type(type = "org.example.DatabaseAwareLobType")
    private String value;
}

The DatabaseAwareLobType looks like:

import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.hibernate.type.descriptor.sql.ClobTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
...

@Component
public class DatabaseAwareLobType extends AbstractSingleColumnStandardBasicType<String> {

    @Value("${spring.jpa.properties.hibernate.dialect}")
    private String dbDialect;

    private static String DBDIALECT_STATIC;

    public static final DatabaseAwareLobType INSTANCE = new DatabaseAwareLobType();

    public DatabaseAwareLobType() {
        super(getDbDescriptor(), StringTypeDescriptor.INSTANCE );
    }
    public static SqlTypeDescriptor getDbDescriptor() {
        if( isPostgres() ) {
            return VarcharTypeDescriptor.INSTANCE;
        }
        else {
            return ClobTypeDescriptor.DEFAULT;
        }
    }

    private static boolean isPostgres() {
        if(Objects.isNull(DBDIALECT_STATIC) ) {
            return false;
        }

        return DBDIALECT_STATIC.contains( "postgres" );
    }

    @Value("${spring.jpa.properties.hibernate.dialect}")
    public void setDbDialectStatic(String dbDialect) {
        DatabaseAwareLobType.DBDIALECT_STATIC = dbDialect;
    }

}

My problem are the dbDialect resp. DBDIALECT_STATIC properties. They have no value, because the hibernate initialization is done before loading the application properties.

In the linked instruction the properties were read manually. I cant to this, because i dont know which property file is used (different spring profiles, customization via docker environment).

I'm searched for loading properties prior application startup, maybe to initialize a bean for the database type. But I have found no suitable solution for my problem. Maybe I'm trying it the wrong way.

Does anyone have an idea how i can solve this? I am thankful for any suggestions.

Upvotes: 1

Views: 363

Answers (1)

Christof Schulz
Christof Schulz

Reputation: 11

So I have found no solution. I have an alternative implementation.

First I changed the attribute type from String to byte[] and used Hibernates BinaryType for mapping it

@Entity
public class MyEntity {

    @EmbeddedId
    private MyPk myPk;

    @Lob
    @Column(name = "data", nullable = false)
    @Type(type="org.hibernate.type.BinaryType")
    private byte[] data;
}

I set up the database with liquibase. The LOB column is no longer from type clob but from blob. So my liquibase-changelog looks like:

<createTable tableName="my_entity" schemaName="importservice">
...
    <column name="data" type="${blob_type}">
        <constraints nullable="false" />
    </column>
</createTable>

And the target database is taken into account by the associated properties for the lob type:

<property name="blob_type" value="bytea" dbms="postgresql"/>
<property name="blob_type" value="blob"/>

So now there is an extra step for converting the byte array in string and vice versa. But this is ok for me.

Upvotes: 0

Related Questions