-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Registering Custom Types using EntityManagerFactory
PostPosted: Thu Apr 07, 2016 9:37 am 
Newbie

Joined: Thu Apr 07, 2016 9:20 am
Posts: 4
Hi all,
been struggling with this for a few weeks now. Using Hibernate 4.3.11 and Spring 4.2.4.

I have some Entities with a primary key of java.util.UUID and a postgres database by default.

This works fine with
Code:
@org.hibernate.annotations.Type(type="pg-uuid")
.

However my unit/integration tests initialise a test context with a H2 db, because, testing, which means that the registered type is now incorrect.

So, what I'd like to be able to do is to configure the Types registry https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch06.html#types-registry using postgres under "default" profile and use "h2" profile for testing.

The problem I'm facing is that our configuration is using spring-orm's HibernateJpaVendorAdapter into a LocalContainerEntityManagerFactoryBean which doesn't appear to allow the underlying configuration to be modified or instantiated via spring.

Does anyone know how I can register the org.hibernate.type.PostgresUUIDType using this configuration?

Code:
@Entity
@Table(name = "models")
public class ModelEntity {

    @Id
    @org.hibernate.annotations.Type(type="pg-uuid") // doesn't work under h2
    private UUID modelId;

    @Basic
    private String name;
}


Code:
@Configuration
public class RealConfig {

    @Value("${driverClass}")
    private String driverClass;

    @Value("${jdbcURL}")
    private String jdbcURL;

    @Value("${username}")
    private String username;

    @Value("${password}")
    private String password;

    @Bean
    @Profile("default")
    public DataSource dataSource() {
        BasicDataSource basicDataSource = new BasicDataSource();
        basicDataSource.setDriverClassName(driverClass);
        basicDataSource.setUrl(jdbcURL);
        basicDataSource.setUsername(username);
        basicDataSource.setPassword(password);
        return basicDataSource;
    }

    @Bean
    @Profile("default")
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
        hibernateJpaVendorAdapter.setShowSql(true);
        hibernateJpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.PostgreSQL9Dialect");
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        localContainerEntityManagerFactoryBean.setDataSource(dataSource);
        localContainerEntityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
        localContainerEntityManagerFactoryBean.setPackagesToScan("my.entities");
        return localContainerEntityManagerFactoryBean;
    }

}


Code:
@Configuration
@Profile("h2")
public class TestDBConfig {

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setDatabase(Database.H2);
        hibernateJpaVendorAdapter.setShowSql(true);
        hibernateJpaVendorAdapter.setGenerateDdl(true);
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public Properties hibernateProperties() {
        final Properties properties = new Properties();

        properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.put("hibernate.connection.driver_class", "org.h2.Driver");
        properties.put("hibernate.hbm2ddl.auto", "create-drop");

        return properties;
    }

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
    }
}


Top
 Profile  
 
 Post subject: Re: Registering Custom Types using EntityManagerFactory
PostPosted: Thu Apr 07, 2016 10:18 am 
Hibernate Team
Hibernate Team

Joined: Thu Sep 11, 2014 2:50 am
Posts: 1630
Location: Romania
You don't need to supply the "pg-uuid" type. You can try without a type definition:

Code:
@Id
private UUID modelId;


When you use PostgreSQL, Hibernate will use the "pg-uuid" type by default. Otherwise it just falls back to a generic UUID generator.


Top
 Profile  
 
 Post subject: Re: Registering Custom Types using EntityManagerFactory
PostPosted: Thu Apr 07, 2016 11:29 am 
Newbie

Joined: Thu Apr 07, 2016 9:20 am
Posts: 4
Thanks for the quick reply mihalcea_vlad.

You're correct in that standard persist/retrieve works fine.

However, when combined with spring data-jpa using JPQL queries with joins you end up getting this error:

org.postgresql.util.PSQLException: ERROR: operator does not exist: uuid = bytes

With the type attribute on the fields, this works.

Also, using an IdClass on a join table with only entity relationships results in the id being retrieved incorrectly unless the Type annotation is present.

I think there is a bug in there because the value being read appears to be bit-shifted/manipulated in a constant way.

e.g.:
Code:
@Entity
@Table(name = "usermodels")
@IdClass(UserModelEntity.UserModelEntityPK.class)
public class UserModelEntity {

    @Id
    @ManyToOne
    @JoinColumn(name = "modelId", nullable = false)
    private ModelEntity modelEntity;

    @Id
    @ManyToOne
    @JoinColumn(name = "userId", nullable = false, referencedColumnName="id")
    private UserEntity userEntity;

    public static final class UserModelEntityPK implements Serializable{

        // without this annotation at the end of a transaction the entity is judged to have changed e.g. uuid 9996a84b-5419-4b67-8c22-de2516cf018e is considered to be 39393936-6138-3462-2d35-3431392d3462
        @org.hibernate.annotations.Type(type="pg-uuid")
        private UUID modelEntity;

        private int userEntity;
    }
}


Top
 Profile  
 
 Post subject: Re: Registering Custom Types using EntityManagerFactory
PostPosted: Thu Apr 07, 2016 12:23 pm 
Hibernate Team
Hibernate Team

Joined: Thu Sep 11, 2014 2:50 am
Posts: 1630
Location: Romania
That exception happens when you pass a null as an argument to a search criteria.

There might be a bug there too, can you provide a replicating test case?


Top
 Profile  
 
 Post subject: Re: Registering Custom Types using EntityManagerFactory
PostPosted: Fri Apr 08, 2016 11:54 am 
Newbie

Joined: Thu Apr 07, 2016 9:20 am
Posts: 4
I've almost finished putting together a nice example of this, and I think I've spotted the main problem.

allowing ddl update to dictate the schema, the column type being created is not the native postgres uuid.

instead it is bytea

see:
column_name data_type character_maximum_length
modelid bytea <null>
active boolean <null>
name character varying 255

as opposed to:
column_name data_type character_maximum_length
modelid uuid <null>
active boolean <null>
name character varying 255

which explains the problem with the JPA query.

I'll have a concrete example ready shortly, will have to liquibase bootstrap to show the issue though.


Top
 Profile  
 
 Post subject: Re: Registering Custom Types using EntityManagerFactory
PostPosted: Fri Apr 08, 2016 2:12 pm 
Newbie

Joined: Thu Apr 07, 2016 9:20 am
Posts: 4
So, Here's an example I've knocked up today.

https://drive.google.com/file/d/0BxRXU9hW1aRxTFlfWVVXUmdaN00/view?usp=sharing

Comment out the @Type annotations on the UUID's and watch the world burn.

won't run in maven because of two entity managers in the same classloader but the tests run well.

works in h2, fails in postgres with uuid column types, or vice versa with the type attribute.

I didn't manage to replicate the id conversion change with these tests, but I'll try again on Monday.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.