Videanu Adrian
Videanu Adrian

Reputation: 970

Hibernate query cache and Hazelcast serialization for JPAAttributeConvertor

I'm currently developing a web application using JSF, Spring (5.3.31), and Hibernate (5.6.15).

Recently, I switched from using EhCache as the second level and query cache for Hibernate to Hazelcast 4.2.5.
To ensure compliance, I'm using Hazelcast as the JCache implementation, with a simple setup of just one Hazelcast node.

While everything appears to work as expected (second-level cache, Spring cache, etc.), I encounter an issue with the query cache when it involves queries that use a parameter that has to use the converter to be applied. Here's an example to illustrate:

@Entity
public class MyEntity extends  BaseEntity {

    private String name;

    @Convert(converter = MyConvertor.class)
    private Integer age;    
}
@Converter
public class MyConvertor implements AttributeConverter<String, Integer>, Serializable {

    public MyConvertor(){
        super();
    }

    @Override
    public Integer convertToDatabaseColumn(String attribute) {

        if(attribute == null) {
            return null;
        }
        return Integer.parseInt(attribute);
    }

    @Override
    public String convertToEntityAttribute(Integer code) {
        
        if(code == null) {
            return null;
        }
            
        return code.toString();
    }
}

in my DAO, I have a method like this:

@Named
public class MyEntityDAOImpl extends GenericDAOImpl<MyEntity> implements MyEntityDAO {

    @Override
    public List<MyEntity> getAll() {

        String sql = "SELECT me FROM MyEntity me WHERE me.age=:mage";
        TypedQuery tq = em.createQuery(sql,MyEntity.class);
        tq.setParameter("mage", "12");
        tq.setHint(HIBERNATE_CACHE_HINT, "true");

        return tq.getResultList()
    }

The problem is that as soon as I call this method I got an :

com.hazelcast.nio.serialization.HazelcastSerializationException: Failed to serialize 'org.hibernate.cache.spi.QueryKey'

going down on trace it seems that all starts from:

Caused by: java.io.NotSerializableException: org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl
    - field (class "org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter", name: "converter", type: "interface org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter")
    - object (class "org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter", org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter@469fb4ce)
    - field (class "org.hibernate.type.AbstractStandardBasicType", name: "sqlTypeDescriptor", type: "interface org.hibernate.type.descriptor.sql.SqlTypeDescriptor")
    - object (class "org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter", BasicType adapter for AttributeConverter<String,Integer>)
    - field (class "org.hibernate.engine.spi.TypedValue", name: "type", type: "interface org.hibernate.type.Type")
    - object (class "org.hibernate.engine.spi.TypedValue", 12)
    - custom writeObject data (class "java.util.HashMap")
    - object (class "java.util.HashMap", {mage=12})
    - field (class "org.hibernate.cache.spi.QueryKey", name: "namedParameters", type: "interface java.util.Map")
    - root object (class "org.hibernate.cache.spi.QueryKey", sql: select myentity0_.id as id1_319_, myentity0_.version as version2_319_, myentity0_.age as age3_319_, myentity0_.name as name4_319_ from my_entities myentity0_ where myentity0_.age=?; parameters: ; named parameters: {mage=12}; transformer: org.hibernate.transform.CacheableResultTransformer@110f2)
    at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1173)
    at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1543)

For this simplified example, I replicated the issue from a more complex entity experiencing the same problem. If I remove the parameter from the query, it functions as expected.

After extensive searching, I haven't found a solution.
Although Hazelcast supports custom serializers, I find it hard to believe that I would need to implement a custom serializer for such a common use case. I suspect I'm missing something here.

Has anyone experienced a similar issue or have any insights on this?

P.S - The reason that I use Hazelcast 4.2 is that the app is running on payara5.x and this is the hazelcast shipped with the application server and I want to avoid classpath/version issues.

Upvotes: 0

Views: 60

Answers (0)

Related Questions