New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with Hibernate custom types and HibernateDomainExporter in 2.8.0 #240

Closed
mirkosertic opened this Issue Oct 1, 2012 · 8 comments

Comments

Projects
None yet
2 participants
@mirkosertic

Hi there

we are getting the following exception in QueryDSL 2.8.0:

org.hibernate.MappingException: Could not determine type for: ch.bedag.gba.capitastra.dao.hibernate.usertypes.GenericEnumUserType, at table: Praefix, for columns: [org.hibernate.mapping.Column(idType)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:316)
at org.hibernate.mapping.Property.getType(Property.java:81)
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:307)
at org.hibernate.mapping.Property.getType(Property.java:81)
at com.mysema.query.jpa.codegen.HibernateDomainExporter.handleProperty(HibernateDomainExporter.java:335)
at com.mysema.query.jpa.codegen.HibernateDomainExporter.collectTypes(HibernateDomainExporter.java:312)
at com.mysema.query.jpa.codegen.HibernateDomainExporter.execute(HibernateDomainExporter.java:231)

when using the following XML mapping:

    <property name="idType" not-null="true">
        <type name="ch.bedag.gba.capitastra.dao.hibernate.usertypes.GenericEnumUserType">
            <param name="className">ch.bedag.gba.capitastra.model.egbv.EgbvIdentifikatorTyp</param>
        </type>
    </property> 

Any ideas how to solve this problem?

Regards
Mirko

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 1, 2012

Member

Thanks for the mapping details, I will take a look.

Member

timowest commented Oct 1, 2012

Thanks for the mapping details, I will take a look.

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 1, 2012

Member

Where can I get ch.bedag.gba.capitastra.dao.hibernate.usertypes.GenericEnumUserType?

Member

timowest commented Oct 1, 2012

Where can I get ch.bedag.gba.capitastra.dao.hibernate.usertypes.GenericEnumUserType?

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 1, 2012

Member

As stated in #238 the official Hibernate user type for enums works well, what does your user type do different?

Member

timowest commented Oct 1, 2012

As stated in #238 the official Hibernate user type for enums works well, what does your user type do different?

@mirkosertic

This comment has been minimized.

Show comment
Hide comment
@mirkosertic

mirkosertic Oct 2, 2012

Hi there

We are not using the enum type, we are really defining types by ourselfs. Here is an example type:

public class GenericEnumUserType extends AbstractUserType implements ParameterizedType {

    @SuppressWarnings("rawtypes")
    private Class<? extends Enum> enumClass;

    private static final int[] SQL_TYPES = { Types.VARCHAR };

    @Override
    public void setParameterValues(Properties parameters) {

        String enumClassName = parameters.getProperty("className");

        try {
            enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
        } catch (ClassNotFoundException cfne) {
            throw new HibernateException("Enum class not found", cfne);
        }
    }

    @Override
    public Class<?> returnedClass() {
        return enumClass;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {

        String str = rs.getString(names[0]);
        if (rs.wasNull()) {
            return null;
        } else {
            try {
                @SuppressWarnings("unchecked")
                Enum<?> enumValue = Enum.valueOf(enumClass, str);
                return enumValue;
            } catch (Exception e) {
                throw new HibernateException("Exception while invoking method Enum.valueOf(..) with enumClass = "
                        + enumClass, e);
            }
        }
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
        try {
            if (value == null) {
                st.setNull(index, SQL_TYPES[0]);
            } else {
                String identifier = ((Enum<?>)value).name();
                st.setString(index, identifier);
            }
        } catch (Exception e) {
            throw new HibernateException("Exception while invoking method name() on enum '" + value + "' (enumClass = "
                    + enumClass + ")", e);
        }
    }

    @Override
    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }
}

The "returningClass" is is an enum, right, but we are using our own custom type for the mapping. Please not that we are not using only custom types for enums, we are using them also for currencies and other things in our domain model, and we are mapping them in the same way as the provided example.

The key is that the obove described type is not part of the Hibernate type registry, and this makes the code generator fail.

Hi there

We are not using the enum type, we are really defining types by ourselfs. Here is an example type:

public class GenericEnumUserType extends AbstractUserType implements ParameterizedType {

    @SuppressWarnings("rawtypes")
    private Class<? extends Enum> enumClass;

    private static final int[] SQL_TYPES = { Types.VARCHAR };

    @Override
    public void setParameterValues(Properties parameters) {

        String enumClassName = parameters.getProperty("className");

        try {
            enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
        } catch (ClassNotFoundException cfne) {
            throw new HibernateException("Enum class not found", cfne);
        }
    }

    @Override
    public Class<?> returnedClass() {
        return enumClass;
    }

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {

        String str = rs.getString(names[0]);
        if (rs.wasNull()) {
            return null;
        } else {
            try {
                @SuppressWarnings("unchecked")
                Enum<?> enumValue = Enum.valueOf(enumClass, str);
                return enumValue;
            } catch (Exception e) {
                throw new HibernateException("Exception while invoking method Enum.valueOf(..) with enumClass = "
                        + enumClass, e);
            }
        }
    }

    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
        try {
            if (value == null) {
                st.setNull(index, SQL_TYPES[0]);
            } else {
                String identifier = ((Enum<?>)value).name();
                st.setString(index, identifier);
            }
        } catch (Exception e) {
            throw new HibernateException("Exception while invoking method name() on enum '" + value + "' (enumClass = "
                    + enumClass + ")", e);
        }
    }

    @Override
    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }
}

The "returningClass" is is an enum, right, but we are using our own custom type for the mapping. Please not that we are not using only custom types for enums, we are using them also for currencies and other things in our domain model, and we are mapping them in the same way as the provided example.

The key is that the obove described type is not part of the Hibernate type registry, and this makes the code generator fail.

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 5, 2012

Member

This usertype is unfortunately incompatible with the Hibernate version used in Querydsl (4.1.7). I tried though to make a copy of the original Hibernate enum type and had no problems to make it work.

The type lookup of Hibernate 4.1.7 uses the type name as the class name

public static Type heuristicType(String typeName, Properties parameters)
        throws MappingException {
    Type type = TypeFactory.basic( typeName );
    if ( type == null ) {
        Class typeClass;
        try {
            typeClass = ReflectHelper.classForName( typeName );
        }
        catch (ClassNotFoundException cnfe) {
            typeClass = null;
        }

Could you maybe check that the class name is correct? Also you user type seems to provide a subset of the functionality of Hibernate's own enum user type.

Member

timowest commented Oct 5, 2012

This usertype is unfortunately incompatible with the Hibernate version used in Querydsl (4.1.7). I tried though to make a copy of the original Hibernate enum type and had no problems to make it work.

The type lookup of Hibernate 4.1.7 uses the type name as the class name

public static Type heuristicType(String typeName, Properties parameters)
        throws MappingException {
    Type type = TypeFactory.basic( typeName );
    if ( type == null ) {
        Class typeClass;
        try {
            typeClass = ReflectHelper.classForName( typeName );
        }
        catch (ClassNotFoundException cnfe) {
            typeClass = null;
        }

Could you maybe check that the class name is correct? Also you user type seems to provide a subset of the functionality of Hibernate's own enum user type.

@mirkosertic

This comment has been minimized.

Show comment
Hide comment
@mirkosertic

mirkosertic Oct 15, 2012

Hi there

Any news about this topic? We cannot upgrade to the latest Hibernate version, and due to the complex nature of our domain model, we cannot change every custom type, as we are using them a lot to persist value objects.

Regards
Mirko

Hi there

Any news about this topic? We cannot upgrade to the latest Hibernate version, and due to the complex nature of our domain model, we cannot change every custom type, as we are using them a lot to persist value objects.

Regards
Mirko

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 15, 2012

Member

Ok, then I will provide a solution that works with your user type.

Member

timowest commented Oct 15, 2012

Ok, then I will provide a solution that works with your user type.

@timowest

This comment has been minimized.

Show comment
Hide comment
@timowest

timowest Oct 19, 2012

Member

Released in 2.8.1

Member

timowest commented Oct 19, 2012

Released in 2.8.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment