Skip to content

Commit

Permalink
HHH-9042 - Envers fails with @converter and AttributeConverter
Browse files Browse the repository at this point in the history
  • Loading branch information
sebersole committed Mar 20, 2015
1 parent 180e714 commit 2273062
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 7 deletions.
Expand Up @@ -1695,4 +1695,9 @@ void cannotResolveNonNullableTransientDependencies(String transientEntityString,
@LogMessage(level = DEBUG)
@Message(value = "Creating pooled optimizer (lo) with [incrementSize=%s; returnClass=%s]", id = 467)
void creatingPooledLoOptimizer(int incrementSize, String name);

@LogMessage(level = WARN)
@Message(value = "Unable to interpret type [%s] as an AttributeConverter due to an exception : %s", id = 468)
void logBadHbmAttributeConverterType(String type, String exceptionMessage);

}
Expand Up @@ -31,8 +31,10 @@
import javax.persistence.AttributeConverter;

import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.AvailableSettings;
Expand All @@ -44,6 +46,8 @@
import org.hibernate.id.IdentityGenerator;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter;
Expand All @@ -55,14 +59,12 @@
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry;
import org.hibernate.usertype.DynamicParameterizedType;

import org.jboss.logging.Logger;

/**
* Any value that maps to columns.
* @author Gavin King
*/
public class SimpleValue implements KeyValue {
private static final Logger log = Logger.getLogger( SimpleValue.class );
private static final CoreMessageLogger log = CoreLogging.messageLogger( SimpleValue.class );

public static final String DEFAULT_ID_GEN_STRATEGY = "assigned";

Expand Down Expand Up @@ -96,6 +98,7 @@ public MetadataImplementor getMetadata() {
return metadata;
}

@Override
public boolean isCascadeDeleteEnabled() {
return cascadeDeleteEnabled;
}
Expand All @@ -113,7 +116,8 @@ public void addColumn(Column column) {
public void addFormula(Formula formula) {
columns.add(formula);
}


@Override
public boolean hasFormula() {
Iterator iter = getColumnIterator();
while ( iter.hasNext() ) {
Expand All @@ -123,34 +127,59 @@ public boolean hasFormula() {
return false;
}

@Override
public int getColumnSpan() {
return columns.size();
}

@Override
public Iterator<Selectable> getColumnIterator() {
return columns.iterator();
}

public List getConstraintColumns() {
return columns;
}

public String getTypeName() {
return typeName;
}
public void setTypeName(String type) {
this.typeName = type;

public void setTypeName(String typeName) {
if ( typeName != null && typeName.startsWith( AttributeConverterTypeAdapter.NAME_PREFIX ) ) {
final String converterClassName = typeName.substring( AttributeConverterTypeAdapter.NAME_PREFIX.length() );
final ClassLoaderService cls = getMetadata().getMetadataBuildingOptions()
.getServiceRegistry()
.getService( ClassLoaderService.class );
try {
final Class<AttributeConverter> converterClass = cls.classForName( converterClassName );
attributeConverterDefinition = new AttributeConverterDefinition( converterClass.newInstance(), false );
return;
}
catch (Exception e) {
log.logBadHbmAttributeConverterType( typeName, e.getMessage() );
}
}

this.typeName = typeName;
}

public void setTable(Table table) {
this.table = table;
}

@Override
public void createForeignKey() throws MappingException {}

@Override
public void createForeignKeyOfEntity(String entityName) {
if ( !hasFormula() && !"none".equals(getForeignKeyName())) {
ForeignKey fk = table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName );
fk.setCascadeDeleteEnabled(cascadeDeleteEnabled);
}
}

@Override
public IdentifierGenerator createIdentifierGenerator(
IdentifierGeneratorFactory identifierGeneratorFactory,
Dialect dialect,
Expand Down Expand Up @@ -445,13 +474,15 @@ private Type buildAttributeConverterTypeAdapter() {

// todo : cache the AttributeConverterTypeAdapter in case that AttributeConverter is applied multiple times.

final String name = String.format(
final String name = AttributeConverterTypeAdapter.NAME_PREFIX + attributeConverterDefinition.getAttributeConverter().getClass().getName();
final String description = String.format(
"BasicType adapter for AttributeConverter<%s,%s>",
entityAttributeJavaType.getSimpleName(),
databaseColumnJavaType.getSimpleName()
);
return new AttributeConverterTypeAdapter(
name,
description,
attributeConverterDefinition.getAttributeConverter(),
sqlTypeDescriptorAdapter,
entityAttributeJavaType,
Expand Down
Expand Up @@ -39,21 +39,26 @@
public class AttributeConverterTypeAdapter<T> extends AbstractSingleColumnStandardBasicType<T> {
private static final Logger log = Logger.getLogger( AttributeConverterTypeAdapter.class );

public static final String NAME_PREFIX = "converted::";

private final String name;
private final String description;

private final Class modelType;
private final Class jdbcType;
private final AttributeConverter<? extends T,?> attributeConverter;

public AttributeConverterTypeAdapter(
String name,
String description,
AttributeConverter<? extends T,?> attributeConverter,
SqlTypeDescriptor sqlTypeDescriptorAdapter,
Class modelType,
Class jdbcType,
JavaTypeDescriptor<T> entityAttributeJavaTypeDescriptor) {
super( sqlTypeDescriptorAdapter, entityAttributeJavaTypeDescriptor );
this.name = name;
this.description = description;
this.modelType = modelType;
this.jdbcType = jdbcType;
this.attributeConverter = attributeConverter;
Expand All @@ -77,4 +82,9 @@ public Class getJdbcType() {
public AttributeConverter<? extends T,?> getAttributeConverter() {
return attributeConverter;
}

@Override
public String toString() {
return description;
}
}
@@ -0,0 +1,70 @@
/*
* 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.envers.test.entities.converter;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
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.cfg.AvailableSettings;
import org.hibernate.envers.test.AbstractEnversTest;
import org.hibernate.mapping.PersistentClass;

import org.hibernate.testing.TestForIssue;
import org.junit.Test;

import static org.junit.Assert.assertNotNull;

/**
* @author Steve Ebersole
*/
public class BasicModelingTest extends AbstractEnversTest {
@Test
@TestForIssue( jiraKey = "HHH-9042" )
public void testMetamodelBuilding() {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder()
.applySetting( AvailableSettings.HBM2DDL_AUTO, "create-drop" )
.build();
try {
Metadata metadata = new MetadataSources( ssr )
.addAttributeConverter( SexConverter.class )
.addAnnotatedClass( Person.class )
.buildMetadata();

( (MetadataImpl) metadata ).validate();

PersistentClass personBinding = metadata.getEntityBinding( Person.class.getName() );
assertNotNull( personBinding );

PersistentClass personAuditBinding = metadata.getEntityBinding( Person.class.getName() + "_AUD" );
assertNotNull( personAuditBinding );
}
finally {
StandardServiceRegistryBuilder.destroy( ssr );
}
}
}
@@ -0,0 +1,47 @@
/*
* 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.envers.test.entities.converter;

import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.Audited;

/**
* @author Steve Ebersole
*/
@Entity
@Audited
public class Person {
@Id
@GeneratedValue( generator = "increment" )
@GenericGenerator( name = "increment", strategy="increment" )
private Long id;

@Convert(converter = SexConverter.class)
private Sex sex;
}
@@ -0,0 +1,32 @@
/*
* 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.envers.test.entities.converter;

/**
* @author Steve Ebersole
*/
public enum Sex {
MALE,
FEMALE;
}

0 comments on commit 2273062

Please sign in to comment.