HHH-9599 - AnnotationException occurs when applying @Nationalized and @Convert annotations to the same field
(cherry picked from commit 38c004431d
)
Conflicts:
hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java
hibernate-core/src/main/java/org/hibernate/cfg/annotations/SimpleValueBinder.java
hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java
This commit is contained in:
parent
b9aced4ab6
commit
44bc5f2f8c
|
@ -78,6 +78,8 @@ import org.jboss.logging.Logger;
|
|||
public class SimpleValueBinder {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, SimpleValueBinder.class.getName());
|
||||
|
||||
private Mappings mappings;
|
||||
|
||||
private String propertyName;
|
||||
private String returnedClassName;
|
||||
private Ejb3Column[] columns;
|
||||
|
@ -85,7 +87,8 @@ public class SimpleValueBinder {
|
|||
private String explicitType = "";
|
||||
private String defaultType = "";
|
||||
private Properties typeParameters = new Properties();
|
||||
private Mappings mappings;
|
||||
private boolean isNationalized;
|
||||
|
||||
private Table table;
|
||||
private SimpleValue simpleValue;
|
||||
private boolean isVersion;
|
||||
|
@ -157,7 +160,7 @@ public class SimpleValueBinder {
|
|||
typeParameters.clear();
|
||||
String type = BinderHelper.ANNOTATION_STRING_DEFAULT;
|
||||
|
||||
final boolean isNationalized = property.isAnnotationPresent( Nationalized.class )
|
||||
isNationalized = property.isAnnotationPresent( Nationalized.class )
|
||||
|| mappings.useNationalizedCharacterData();
|
||||
|
||||
Type annType = property.getAnnotation( Type.class );
|
||||
|
@ -387,6 +390,9 @@ public class SimpleValueBinder {
|
|||
table = columns[0].getTable();
|
||||
}
|
||||
simpleValue = new SimpleValue( mappings, table );
|
||||
if ( isNationalized ) {
|
||||
simpleValue.makeNationalized();
|
||||
}
|
||||
|
||||
linkWithValue();
|
||||
|
||||
|
@ -407,7 +413,7 @@ public class SimpleValueBinder {
|
|||
if ( columns[0].isNameDeferred() && !mappings.isInSecondPass() && referencedEntityName != null ) {
|
||||
mappings.addSecondPass(
|
||||
new PkDrivenByDefaultMapsIdSecondPass(
|
||||
referencedEntityName, ( Ejb3JoinColumn[] ) columns, simpleValue
|
||||
referencedEntityName, (Ejb3JoinColumn[]) columns, simpleValue
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
|
|||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry;
|
||||
import org.hibernate.type.descriptor.sql.JdbcTypeJavaClassMappings;
|
||||
import org.hibernate.type.descriptor.sql.NationalizedTypeMappings;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry;
|
||||
import org.hibernate.usertype.DynamicParameterizedType;
|
||||
|
@ -69,13 +70,15 @@ public class SimpleValue implements KeyValue {
|
|||
private final List<Selectable> columns = new ArrayList<Selectable>();
|
||||
|
||||
private String typeName;
|
||||
private Properties typeParameters;
|
||||
private boolean isNationalized;
|
||||
|
||||
private Properties identifierGeneratorProperties;
|
||||
private String identifierGeneratorStrategy = DEFAULT_ID_GEN_STRATEGY;
|
||||
private String nullValue;
|
||||
private Table table;
|
||||
private String foreignKeyName;
|
||||
private boolean alternateUniqueKey;
|
||||
private Properties typeParameters;
|
||||
private boolean cascadeDeleteEnabled;
|
||||
|
||||
private AttributeConverterDefinition attributeConverterDefinition;
|
||||
|
@ -136,6 +139,15 @@ public class SimpleValue implements KeyValue {
|
|||
public void setTypeName(String type) {
|
||||
this.typeName = type;
|
||||
}
|
||||
|
||||
public void makeNationalized() {
|
||||
this.isNationalized = true;
|
||||
}
|
||||
|
||||
public boolean isNationalized() {
|
||||
return isNationalized;
|
||||
}
|
||||
|
||||
public void setTable(Table table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
@ -318,6 +330,7 @@ public class SimpleValue implements KeyValue {
|
|||
if ( typeName == null ) {
|
||||
throw new MappingException( "No type name" );
|
||||
}
|
||||
|
||||
if ( typeParameters != null
|
||||
&& Boolean.valueOf( typeParameters.getProperty( DynamicParameterizedType.IS_DYNAMIC ) )
|
||||
&& typeParameters.get( DynamicParameterizedType.PARAMETER_TYPE ) == null ) {
|
||||
|
@ -360,6 +373,10 @@ public class SimpleValue implements KeyValue {
|
|||
throw new MappingException( "you must specify types for a dynamic entity: " + propertyName );
|
||||
}
|
||||
typeName = ReflectHelper.reflectedPropertyClass( className, propertyName ).getName();
|
||||
// todo : to fully support isNationalized here we need do the process hinted at above
|
||||
// essentially, much of the logic from #buildAttributeConverterTypeAdapter wrt resolving
|
||||
// a (1) SqlTypeDescriptor, a (2) JavaTypeDescriptor and dynamically building a BasicType
|
||||
// combining them.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -419,7 +436,10 @@ public class SimpleValue implements KeyValue {
|
|||
// corresponding to the AttributeConverter's declared "databaseColumnJavaType" (how we read that value out
|
||||
// of ResultSets). See JdbcTypeJavaClassMappings for details. Again, given example, this should return
|
||||
// VARCHAR/CHAR
|
||||
final int jdbcTypeCode = JdbcTypeJavaClassMappings.INSTANCE.determineJdbcTypeCodeForJavaClass( databaseColumnJavaType );
|
||||
int jdbcTypeCode = JdbcTypeJavaClassMappings.INSTANCE.determineJdbcTypeCodeForJavaClass( databaseColumnJavaType );
|
||||
if ( isNationalized() ) {
|
||||
jdbcTypeCode = NationalizedTypeMappings.INSTANCE.getCorrespondingNationalizedCode( jdbcTypeCode );
|
||||
}
|
||||
// find the standard SqlTypeDescriptor for that JDBC type code.
|
||||
final SqlTypeDescriptor sqlTypeDescriptor = SqlTypeDescriptorRegistry.INSTANCE.getDescriptor( jdbcTypeCode );
|
||||
// find the JavaTypeDescriptor representing the "intermediate database type representation". Back to the
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.type.descriptor.sql;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Manages a mapping between nationalized and non-nationalized variants of JDBC types.
|
||||
*
|
||||
* At the moment we only care about being able to map non-nationalized codes to the
|
||||
* corresponding nationalized equivalent, so that's all we implement for now
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NationalizedTypeMappings {
|
||||
private static final Logger log = Logger.getLogger( NationalizedTypeMappings.class );
|
||||
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NationalizedTypeMappings INSTANCE = new NationalizedTypeMappings();
|
||||
|
||||
private final Map<Integer,Integer> nationalizedCodeByNonNationalized;
|
||||
|
||||
public NationalizedTypeMappings() {
|
||||
this.nationalizedCodeByNonNationalized = new BoundedConcurrentHashMap<Integer, Integer>();
|
||||
map( Types.CHAR, Types.NCHAR );
|
||||
map( Types.CLOB, Types.NCLOB );
|
||||
map( Types.LONGVARCHAR, Types.LONGNVARCHAR );
|
||||
map( Types.VARCHAR, Types.NVARCHAR );
|
||||
}
|
||||
|
||||
private void map(int nonNationalizedCode, int nationalizedCode) {
|
||||
nationalizedCodeByNonNationalized.put( nonNationalizedCode, nationalizedCode );
|
||||
}
|
||||
|
||||
public int getCorrespondingNationalizedCode(int jdbcCode) {
|
||||
Integer nationalizedCode = nationalizedCodeByNonNationalized.get( jdbcCode );
|
||||
if ( nationalizedCode == null ) {
|
||||
log.debug( "Unable to locate nationalized jdbc-code equivalent for given jdbc code : " + jdbcCode );
|
||||
return jdbcCode;
|
||||
}
|
||||
return nationalizedCode;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2015, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.type.converter;
|
||||
|
||||
import java.sql.Types;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Nationalized;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.internal.MetadataImpl;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Test the combination of @Nationalized and @Convert
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AndNationalizedTests extends BaseUnitTestCase {
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-9599")
|
||||
public void basicTest() {
|
||||
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build();
|
||||
try {
|
||||
Metadata metadata = new MetadataSources( ssr ).addAnnotatedClass( TestEntity.class ).buildMetadata();
|
||||
( (MetadataImpl) metadata ).validate();
|
||||
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( TestEntity.class.getName() );
|
||||
assertEquals(
|
||||
Types.NVARCHAR,
|
||||
entityBinding.getProperty( "name" ).getType().sqlTypes( metadata )[0]
|
||||
);
|
||||
}
|
||||
finally {
|
||||
StandardServiceRegistryBuilder.destroy( ssr );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity")
|
||||
@Table(name = "TestEntity")
|
||||
public static class TestEntity {
|
||||
@Id
|
||||
public Integer id;
|
||||
@Nationalized
|
||||
@Convert(converter = NameConverter.class)
|
||||
public Name name;
|
||||
}
|
||||
|
||||
public static class Name {
|
||||
private final String text;
|
||||
|
||||
public Name(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NameConverter implements AttributeConverter<Name,String> {
|
||||
@Override
|
||||
public String convertToDatabaseColumn(Name attribute) {
|
||||
return attribute.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Name convertToEntityAttribute(String dbData) {
|
||||
return new Name( dbData );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue