diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java index a7498d69a4..7b122a6774 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java @@ -31,18 +31,22 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; + import javax.persistence.AccessType; +import javax.persistence.AttributeConverter; import org.dom4j.Document; import org.dom4j.Element; -import org.jboss.logging.Logger; - import org.hibernate.AnnotationException; +import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; +import org.jboss.logging.Logger; /** * @author Emmanuel Bernard + * @author Brett Meyer */ public class XMLContext implements Serializable { private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, XMLContext.class.getName()); @@ -51,6 +55,8 @@ public class XMLContext implements Serializable { private Map defaultsOverriding = new HashMap(); private List defaultElements = new ArrayList(); private List defaultEntityListeners = new ArrayList(); + private Map localAttributeConverterDefintions + = new HashMap(); private boolean hasContext = false; /** @@ -104,6 +110,8 @@ public class XMLContext implements Serializable { unitElement = root.element( "access" ); setAccess( unitElement, entityMappingDefault ); defaultElements.add( root ); + + setLocalAttributeConverterDefintions( root.elements( "converter" ) ); List entities = root.elements( "entity" ); addClass( entities, packageName, entityMappingDefault, addedClasses ); @@ -184,6 +192,26 @@ public class XMLContext implements Serializable { addedClasses.addAll( localAddedClasses ); return localAddedClasses; } + + private void setLocalAttributeConverterDefintions(List converterElements) { + for (Element converterElement : converterElements) { + try { + final String className = converterElement.attributeValue( "class" ); + final Class attributeConverterClass = ReflectHelper.classForName( + className ); + final AttributeConverter attributeConverter = attributeConverterClass.newInstance(); + final String autoApplyAttribute = converterElement.attributeValue( "auto-apply" ); + final boolean autoApply = autoApplyAttribute != null + ? Boolean.parseBoolean( autoApplyAttribute ) : false; + final AttributeConverterDefinition attrDef = new AttributeConverterDefinition( + attributeConverter, autoApply ); + localAttributeConverterDefintions.put( className, attrDef ); + } + catch (Exception e) { + throw new AnnotationException( "Unable to process a converter -- check your xml configuration.", e ); + } + } + } public static String buildSafeClassName(String className, String defaultPackageName) { if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) { @@ -306,4 +334,15 @@ public class XMLContext implements Serializable { public List getDefaultEntityListeners() { return defaultEntityListeners; } + + /** + * Supplies local converters defined in the parsed orm.xml () for use with JPA attribute + * conversion. Defined here so that converters can be applied within the scope of the orm.xml mappings, rather + * than globally. + * + * @return Map The local attribute converters + */ + public Map getLocalAttributeConverterDefintions() { + return localAttributeConverterDefintions; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/type/AttributeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/type/AttributeConverterTest.java index 34d547a075..824e4b54f2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/type/AttributeConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/type/AttributeConverterTest.java @@ -23,15 +23,21 @@ */ package org.hibernate.test.type; +import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + +import java.io.Serializable; +import java.sql.Timestamp; +import java.sql.Types; + import javax.persistence.AttributeConverter; import javax.persistence.Convert; import javax.persistence.Converter; import javax.persistence.Entity; import javax.persistence.Id; -import java.io.Serializable; -import java.sql.Clob; -import java.sql.Timestamp; -import java.sql.Types; import org.hibernate.IrrelevantEntity; import org.hibernate.Session; @@ -39,28 +45,20 @@ import org.hibernate.SessionFactory; import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; +import org.hibernate.internal.util.ConfigHelper; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.mapping.SimpleValue; +import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.type.AbstractStandardBasicType; import org.hibernate.type.BasicType; import org.hibernate.type.Type; import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter; -import org.hibernate.type.descriptor.java.JdbcTimestampTypeDescriptor; import org.hibernate.type.descriptor.java.StringTypeDescriptor; - import org.junit.Test; -import org.hibernate.testing.FailureExpected; -import org.hibernate.testing.junit4.BaseUnitTestCase; - -import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - /** * Tests the principle of adding "AttributeConverter" to the mix of {@link org.hibernate.type.Type} resolution * @@ -121,6 +119,28 @@ public class AttributeConverterTest extends BaseUnitTestCase { } } + @Test + @TestForIssue(jiraKey = "HHH-8462") + @FailureExpected(jiraKey = "HHH-8462") + public void testBasicOrmXmlConverterApplication() { + Configuration cfg = new Configuration(); + cfg.addAnnotatedClass( Tester.class ); + cfg.addURL( ConfigHelper.findAsResource( "org/hibernate/test/type/orm.xml") ); + cfg.buildMappings(); + + { + PersistentClass tester = cfg.getClassMapping( Tester.class.getName() ); + Property nameProp = tester.getProperty( "name" ); + SimpleValue nameValue = (SimpleValue) nameProp.getValue(); + Type type = nameValue.getType(); + assertNotNull( type ); + assertTyping( BasicType.class, type ); + AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); + assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); + assertEquals( Types.CLOB, basicType.getSqlTypeDescriptor().getSqlType() ); + } + } + @Test @FailureExpected( jiraKey = "HHH-8449" ) public void testBasicConverterDisableApplication() { @@ -222,6 +242,8 @@ public class AttributeConverterTest extends BaseUnitTestCase { sf.close(); } } + + // Entity declarations used in the test ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -349,19 +371,6 @@ public class AttributeConverterTest extends BaseUnitTestCase { } } - @Converter( autoApply = true ) - public static class StringClobConverter implements AttributeConverter { - @Override - public Clob convertToDatabaseColumn(String attribute) { - return null; - } - - @Override - public String convertToEntityAttribute(Clob dbData) { - return null; - } - } - @Converter( autoApply = true ) public static class IntegerToVarcharConverter implements AttributeConverter { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/type/StringClobConverter.java b/hibernate-core/src/test/java/org/hibernate/test/type/StringClobConverter.java new file mode 100644 index 0000000000..69974ebaab --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/type/StringClobConverter.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * This copyrighted material is made available to anyone wishing to use, + * modify, copy, or redistribute it subject to the terms and conditions + * of the GNU Lesser General Public License, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * You should have received a copy of the GNU Lesser General Public License, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +package org.hibernate.test.type; + +import java.sql.Clob; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * @author Brett Meyer + */ +@Converter( autoApply = true ) +public class StringClobConverter implements AttributeConverter { + + @Override + public Clob convertToDatabaseColumn(String attribute) { + return null; + } + + @Override + public String convertToEntityAttribute(Clob dbData) { + return null; + } +} diff --git a/hibernate-core/src/test/resources/org/hibernate/test/type/orm.xml b/hibernate-core/src/test/resources/org/hibernate/test/type/orm.xml new file mode 100644 index 0000000000..d71f093d6b --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/type/orm.xml @@ -0,0 +1,8 @@ + + + + org.hibernate.test.type + +