HHH-7300 - TypeDefs won't be found depending of files read-order
This commit is contained in:
parent
e9d00d4b35
commit
8fa530a247
|
@ -96,6 +96,7 @@ import org.hibernate.mapping.TypeDef;
|
||||||
import org.hibernate.mapping.UnionSubclass;
|
import org.hibernate.mapping.UnionSubclass;
|
||||||
import org.hibernate.mapping.UniqueKey;
|
import org.hibernate.mapping.UniqueKey;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.DiscriminatorType;
|
import org.hibernate.type.DiscriminatorType;
|
||||||
import org.hibernate.type.ForeignKeyDirection;
|
import org.hibernate.type.ForeignKeyDirection;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -1213,6 +1214,11 @@ public final class HbmBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveAndBindTypeDef(simpleValue, mappings, typeName, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resolveAndBindTypeDef(SimpleValue simpleValue,
|
||||||
|
Mappings mappings, String typeName, Properties parameters) {
|
||||||
TypeDef typeDef = mappings.getTypeDef( typeName );
|
TypeDef typeDef = mappings.getTypeDef( typeName );
|
||||||
if ( typeDef != null ) {
|
if ( typeDef != null ) {
|
||||||
typeName = typeDef.getTypeClass();
|
typeName = typeDef.getTypeClass();
|
||||||
|
@ -1222,6 +1228,19 @@ public final class HbmBinder {
|
||||||
allParameters.putAll( typeDef.getParameters() );
|
allParameters.putAll( typeDef.getParameters() );
|
||||||
allParameters.putAll( parameters );
|
allParameters.putAll( parameters );
|
||||||
parameters = allParameters;
|
parameters = allParameters;
|
||||||
|
}else if (typeName!=null && !mappings.isInSecondPass()){
|
||||||
|
BasicType basicType=mappings.getTypeResolver().basic(typeName);
|
||||||
|
if (basicType==null) {
|
||||||
|
/*
|
||||||
|
* If the referenced typeName isn't a basic-type, it's probably a typedef defined
|
||||||
|
* in a mapping file not read yet.
|
||||||
|
* It should be solved by deferring the resolution and binding of this type until
|
||||||
|
* all mapping files are read - the second passes.
|
||||||
|
* Fixes issue HHH-7300
|
||||||
|
*/
|
||||||
|
SecondPass resolveUserTypeMappingSecondPass=new ResolveUserTypeMappingSecondPass(simpleValue,typeName,mappings,parameters);
|
||||||
|
mappings.addSecondPass(resolveUserTypeMappingSecondPass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !parameters.isEmpty() ) simpleValue.setTypeParameters( parameters );
|
if ( !parameters.isEmpty() ) simpleValue.setTypeParameters( parameters );
|
||||||
|
@ -3149,4 +3168,27 @@ public final class HbmBinder {
|
||||||
private static interface EntityElementHandler {
|
private static interface EntityElementHandler {
|
||||||
public void handleEntity(String entityName, String className, Mappings mappings);
|
public void handleEntity(String entityName, String className, Mappings mappings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ResolveUserTypeMappingSecondPass implements SecondPass{
|
||||||
|
|
||||||
|
private SimpleValue simpleValue;
|
||||||
|
private String typeName;
|
||||||
|
private Mappings mappings;
|
||||||
|
private Properties parameters;
|
||||||
|
|
||||||
|
public ResolveUserTypeMappingSecondPass(SimpleValue simpleValue,
|
||||||
|
String typeName, Mappings mappings, Properties parameters) {
|
||||||
|
this.simpleValue=simpleValue;
|
||||||
|
this.typeName=typeName;
|
||||||
|
this.parameters=parameters;
|
||||||
|
this.mappings=mappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doSecondPass(java.util.Map persistentClasses)
|
||||||
|
throws MappingException {
|
||||||
|
resolveAndBindTypeDef(simpleValue, mappings, typeName, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
package org.hibernate.test.mapping.usertypes;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.usertype.ParameterizedType;
|
||||||
|
import org.hibernate.usertype.UserType;
|
||||||
|
|
||||||
|
public class EnumUserType implements UserType, ParameterizedType {
|
||||||
|
|
||||||
|
private Class clazz = null;
|
||||||
|
|
||||||
|
public static EnumUserType createInstance(Class clazz){
|
||||||
|
if (!clazz.isEnum())
|
||||||
|
throw new IllegalArgumentException("Parameter has to be an enum-class");
|
||||||
|
EnumUserType that=new EnumUserType();
|
||||||
|
Properties p=new Properties();
|
||||||
|
p.setProperty("enumClassName", clazz.getName());
|
||||||
|
that.setParameterValues(p);
|
||||||
|
return that;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParameterValues(Properties params) {
|
||||||
|
String enumClassName = params.getProperty("enumClassName");
|
||||||
|
if (enumClassName == null) {
|
||||||
|
throw new MappingException("enumClassName parameter not specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.clazz = Class.forName(enumClassName);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new MappingException("enumClass " + enumClassName + " not found", e);
|
||||||
|
}
|
||||||
|
if (!this.clazz.isEnum()){
|
||||||
|
throw new MappingException("enumClass "+enumClassName+" doesn't refer to an Enum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int[] SQL_TYPES = {Types.CHAR};
|
||||||
|
public int[] sqlTypes() {
|
||||||
|
return SQL_TYPES;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class returnedClass() {
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
|
||||||
|
throws HibernateException, SQLException {
|
||||||
|
String name = resultSet.getString(names[0]);
|
||||||
|
Object result = null;
|
||||||
|
if (!resultSet.wasNull()) {
|
||||||
|
result = Enum.valueOf(clazz, name.trim());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object nullSafeGet(ResultSet resultSet, String[] names,
|
||||||
|
SessionImplementor session, Object owner) throws HibernateException,
|
||||||
|
SQLException {
|
||||||
|
return nullSafeGet(resultSet, names, owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index)
|
||||||
|
throws HibernateException, SQLException {
|
||||||
|
if (null == value) {
|
||||||
|
preparedStatement.setNull(index, Types.VARCHAR);
|
||||||
|
} else {
|
||||||
|
preparedStatement.setString(index, ((Enum)value).name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index,
|
||||||
|
SessionImplementor session) throws HibernateException, SQLException {
|
||||||
|
nullSafeSet(preparedStatement, value, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object deepCopy(Object value) throws HibernateException{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMutable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object assemble(Serializable cached, Object owner) throws HibernateException {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Serializable disassemble(Object value) throws HibernateException {
|
||||||
|
return (Serializable)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object replace(Object original, Object target, Object owner) throws HibernateException {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
public int hashCode(Object x) throws HibernateException {
|
||||||
|
return x.hashCode();
|
||||||
|
}
|
||||||
|
public boolean equals(Object x, Object y) throws HibernateException {
|
||||||
|
if (x == y)
|
||||||
|
return true;
|
||||||
|
if (null == x || null == y)
|
||||||
|
return false;
|
||||||
|
return x.equals(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
|
<hibernate-mapping>
|
||||||
|
<class name="org.hibernate.test.mapping.usertypes.TestEntity"
|
||||||
|
table="TestTable">
|
||||||
|
<id name="id" column="ID" type="integer">
|
||||||
|
<generator class="uuid"/>
|
||||||
|
</id>
|
||||||
|
|
||||||
|
<property name="testEnum" column="ENUM" type="testenumtype"/>
|
||||||
|
</class>
|
||||||
|
</hibernate-mapping>
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.hibernate.test.mapping.usertypes;
|
||||||
|
|
||||||
|
public class TestEntity {
|
||||||
|
private int id;
|
||||||
|
private TestEnum testEnum;
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setTestEnum(TestEnum testEnum) {
|
||||||
|
this.testEnum = testEnum;
|
||||||
|
}
|
||||||
|
public TestEnum getTestEnum() {
|
||||||
|
return testEnum;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package org.hibernate.test.mapping.usertypes;
|
||||||
|
|
||||||
|
public enum TestEnum {
|
||||||
|
FOO,
|
||||||
|
BAR;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
|
<hibernate-mapping>
|
||||||
|
<typedef name="testenumtype" class="org.hibernate.test.mapping.usertypes.EnumUserType">
|
||||||
|
<param name="enumClassName">org.hibernate.test.mapping.usertypes.TestEnum</param>
|
||||||
|
</typedef>
|
||||||
|
</hibernate-mapping>
|
|
@ -0,0 +1,58 @@
|
||||||
|
package org.hibernate.test.mapping.usertypes;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.ServiceRegistryBuilder;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
|
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for read-order independent resolution of user-defined types
|
||||||
|
* Testcase for issue HHH-7300
|
||||||
|
* @author Stefan Schulze
|
||||||
|
*/
|
||||||
|
@TestForIssue(jiraKey = "HHH-7300")
|
||||||
|
public class UserTypeMappingTest extends BaseUnitTestCase{
|
||||||
|
|
||||||
|
private Configuration cfg;
|
||||||
|
private ServiceRegistry serviceRegistry;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup(){
|
||||||
|
cfg=new Configuration();
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.put( Environment.DIALECT, "org.hibernate.dialect.HSQLDialect" );
|
||||||
|
p.put( "hibernate.connection.driver_class", "org.h2.Driver" );
|
||||||
|
p.put( "hibernate.connection.url", "jdbc:h2:mem:" );
|
||||||
|
p.put( "hibernate.connection.username", "sa" );
|
||||||
|
p.put( "hibernate.connection.password", "" );
|
||||||
|
cfg.setProperties(p);
|
||||||
|
serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( cfg.getProperties() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFirstTypeThenEntity(){
|
||||||
|
cfg.addResource("org/hibernate/test/mapping/usertypes/TestEnumType.hbm.xml")
|
||||||
|
.addResource("org/hibernate/test/mapping/usertypes/TestEntity.hbm.xml");
|
||||||
|
SessionFactory sessions=cfg.buildSessionFactory(serviceRegistry);
|
||||||
|
Assert.assertNotNull(sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFirstEntityThenType(){
|
||||||
|
cfg.addResource("org/hibernate/test/mapping/usertypes/TestEntity.hbm.xml")
|
||||||
|
.addResource("org/hibernate/test/mapping/usertypes/TestEnumType.hbm.xml");
|
||||||
|
|
||||||
|
SessionFactory sessions=cfg.buildSessionFactory(serviceRegistry);
|
||||||
|
Assert.assertNotNull(sessions);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue