HHH-8462 Handle <converter></converter> elements in orm.xml

This commit is contained in:
Brett Meyer 2013-09-04 18:13:29 -04:00
parent 151dd1531b
commit 9acb43599b
4 changed files with 130 additions and 31 deletions

View File

@ -31,18 +31,22 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.persistence.AccessType; import javax.persistence.AccessType;
import javax.persistence.AttributeConverter;
import org.dom4j.Document; import org.dom4j.Document;
import org.dom4j.Element; import org.dom4j.Element;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
/** /**
* @author Emmanuel Bernard * @author Emmanuel Bernard
* @author Brett Meyer
*/ */
public class XMLContext implements Serializable { public class XMLContext implements Serializable {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, XMLContext.class.getName()); private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, XMLContext.class.getName());
@ -51,6 +55,8 @@ public class XMLContext implements Serializable {
private Map<String, Default> defaultsOverriding = new HashMap<String, Default>(); private Map<String, Default> defaultsOverriding = new HashMap<String, Default>();
private List<Element> defaultElements = new ArrayList<Element>(); private List<Element> defaultElements = new ArrayList<Element>();
private List<String> defaultEntityListeners = new ArrayList<String>(); private List<String> defaultEntityListeners = new ArrayList<String>();
private Map<String, AttributeConverterDefinition> localAttributeConverterDefintions
= new HashMap<String, AttributeConverterDefinition>();
private boolean hasContext = false; private boolean hasContext = false;
/** /**
@ -104,6 +110,8 @@ public class XMLContext implements Serializable {
unitElement = root.element( "access" ); unitElement = root.element( "access" );
setAccess( unitElement, entityMappingDefault ); setAccess( unitElement, entityMappingDefault );
defaultElements.add( root ); defaultElements.add( root );
setLocalAttributeConverterDefintions( root.elements( "converter" ) );
List<Element> entities = root.elements( "entity" ); List<Element> entities = root.elements( "entity" );
addClass( entities, packageName, entityMappingDefault, addedClasses ); addClass( entities, packageName, entityMappingDefault, addedClasses );
@ -184,6 +192,26 @@ public class XMLContext implements Serializable {
addedClasses.addAll( localAddedClasses ); addedClasses.addAll( localAddedClasses );
return localAddedClasses; return localAddedClasses;
} }
private void setLocalAttributeConverterDefintions(List<Element> converterElements) {
for (Element converterElement : converterElements) {
try {
final String className = converterElement.attributeValue( "class" );
final Class<? extends AttributeConverter> 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) { public static String buildSafeClassName(String className, String defaultPackageName) {
if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) { if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) {
@ -306,4 +334,15 @@ public class XMLContext implements Serializable {
public List<String> getDefaultEntityListeners() { public List<String> getDefaultEntityListeners() {
return defaultEntityListeners; return defaultEntityListeners;
} }
/**
* Supplies local converters defined in the parsed orm.xml (<converter .../>) 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<String, AttributeConverterDefinition> The local attribute converters
*/
public Map<String, AttributeConverterDefinition> getLocalAttributeConverterDefintions() {
return localAttributeConverterDefintions;
}
} }

View File

@ -23,15 +23,21 @@
*/ */
package org.hibernate.test.type; 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.AttributeConverter;
import javax.persistence.Convert; import javax.persistence.Convert;
import javax.persistence.Converter; import javax.persistence.Converter;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Id; 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.IrrelevantEntity;
import org.hibernate.Session; import org.hibernate.Session;
@ -39,28 +45,20 @@ import org.hibernate.SessionFactory;
import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Configuration;
import org.hibernate.internal.util.ConfigHelper;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.SimpleValue; 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.AbstractStandardBasicType;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter; import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
import org.hibernate.type.descriptor.java.JdbcTimestampTypeDescriptor;
import org.hibernate.type.descriptor.java.StringTypeDescriptor; import org.hibernate.type.descriptor.java.StringTypeDescriptor;
import org.junit.Test; 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 * 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 @Test
@FailureExpected( jiraKey = "HHH-8449" ) @FailureExpected( jiraKey = "HHH-8449" )
public void testBasicConverterDisableApplication() { public void testBasicConverterDisableApplication() {
@ -222,6 +242,8 @@ public class AttributeConverterTest extends BaseUnitTestCase {
sf.close(); sf.close();
} }
} }
// Entity declarations used in the test ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity declarations used in the test ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -349,19 +371,6 @@ public class AttributeConverterTest extends BaseUnitTestCase {
} }
} }
@Converter( autoApply = true )
public static class StringClobConverter implements AttributeConverter<String,Clob> {
@Override
public Clob convertToDatabaseColumn(String attribute) {
return null;
}
@Override
public String convertToEntityAttribute(Clob dbData) {
return null;
}
}
@Converter( autoApply = true ) @Converter( autoApply = true )
public static class IntegerToVarcharConverter implements AttributeConverter<Integer,String> { public static class IntegerToVarcharConverter implements AttributeConverter<Integer,String> {
@Override @Override

View File

@ -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<String,Clob> {
@Override
public Clob convertToDatabaseColumn(String attribute) {
return null;
}
@Override
public String convertToEntityAttribute(Clob dbData) {
return null;
}
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.1" >
<package>org.hibernate.test.type</package>
<converter class="org.hibernate.test.type.StringClobConverter" auto-apply="true"/>
</entity-mappings>