HHH-11173 - Fix text serialization of uninitialized lazy attributes

This commit is contained in:
barreiro 2016-10-19 12:04:51 +01:00 committed by Gail Badner
parent 4dad087b39
commit 4d6cda1548
8 changed files with 167 additions and 16 deletions

View File

@ -13,8 +13,10 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -288,6 +290,9 @@ public abstract class AbstractStandardBasicType<T>
@Override
@SuppressWarnings({ "unchecked" })
public final String toLoggableString(Object value, SessionFactoryImplementor factory) {
if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY || !Hibernate.isInitialized( value ) ) {
return "<uninitialized>";
}
return javaTypeDescriptor.extractLoggableRepresentation( (T) value );
}

View File

@ -18,10 +18,12 @@ import java.util.Set;
import org.hibernate.EntityMode;
import org.hibernate.EntityNameResolver;
import org.hibernate.FetchMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.TransientObjectException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.CascadeStyle;
@ -304,11 +306,14 @@ public class AnyType extends AbstractType implements CompositeType, AssociationT
@Override
public String toLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
//TODO: terrible implementation!
return value == null
? "null"
: factory.getTypeHelper()
.entity( HibernateProxyHelper.getClassWithoutInitializingProxy( value ) )
.toLoggableString( value, factory );
if ( value == null ) {
return "null";
}
if ( value == LazyPropertyInitializer.UNFETCHED_PROPERTY || !Hibernate.isInitialized( value ) ) {
return "<uninitialized>";
}
Class valueClass = HibernateProxyHelper.getClassWithoutInitializingProxy( value );
return factory.getTypeHelper().entity( valueClass ).toLoggableString( value, factory );
}
@Override

View File

@ -14,7 +14,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.collection.internal.PersistentArrayHolder;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -74,7 +76,13 @@ public class ArrayType extends CollectionType {
List list = new ArrayList(length);
Type elemType = getElementType(factory);
for ( int i=0; i<length; i++ ) {
list.add( elemType.toLoggableString( Array.get(value, i), factory ) );
Object element = Array.get(value, i);
if ( element == LazyPropertyInitializer.UNFETCHED_PROPERTY || !Hibernate.isInitialized( element ) ) {
list.add( "<uninitialized>" );
}
else {
list.add( elemType.toLoggableString( element, factory ) );
}
}
return list.toString();
}

View File

@ -24,6 +24,7 @@ import org.hibernate.EntityMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.collection.internal.AbstractPersistentCollection;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.jdbc.Size;
@ -194,13 +195,7 @@ public abstract class CollectionType extends AbstractType implements Association
}
}
}
if ( !Hibernate.isInitialized( value ) ) {
return "<uninitialized>";
}
else {
return renderLoggableString( value, factory );
}
return renderLoggableString( value, factory );
}
protected String renderLoggableString(Object value, SessionFactoryImplementor factory) throws HibernateException {
@ -208,7 +203,13 @@ public abstract class CollectionType extends AbstractType implements Association
Type elemType = getElementType( factory );
Iterator itr = getElementsIterator( value );
while ( itr.hasNext() ) {
list.add( elemType.toLoggableString( itr.next(), factory ) );
Object element = itr.next();
if ( element == LazyPropertyInitializer.UNFETCHED_PROPERTY || !Hibernate.isInitialized( element ) ) {
list.add( "<uninitialized>" );
}
else {
list.add( elemType.toLoggableString( element, factory ) );
}
}
return list.toString();
}

View File

@ -20,6 +20,7 @@ import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.jdbc.Size;
import org.hibernate.engine.spi.CascadeStyle;
import org.hibernate.engine.spi.Mapping;
@ -472,7 +473,12 @@ public class ComponentType extends AbstractType implements CompositeType, Proced
Map<String, String> result = new HashMap<>();
Object[] values = getPropertyValues( value, entityMode );
for ( int i = 0; i < propertyTypes.length; i++ ) {
result.put( propertyNames[i], propertyTypes[i].toLoggableString( values[i], factory ) );
if ( values[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
result.put( propertyNames[i], "<uninitialized>" );
}
else {
result.put( propertyNames[i], propertyTypes[i].toLoggableString( values[i], factory ) );
}
}
return StringHelper.unqualify( getName() ) + result.toString();
}

View File

@ -10,6 +10,7 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -374,7 +375,14 @@ public class TypeHelper {
if ( i > 0 ) {
buff.append( ", " );
}
buff.append( types[i].toLoggableString( state[i], factory ) );
// HHH-11173 - Instead of having to account for unfectched lazy properties in all types, it's done here
if ( state[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY || !Hibernate.isInitialized( state[i] ) ) {
buff.append( "<uninitialized>" );
}
else {
buff.append( types[i].toLoggableString( state[i], factory ) );
}
}
return buff.toString();
}

View File

@ -41,6 +41,7 @@ import org.hibernate.test.bytecode.enhancement.lazy.LazyLoadingTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.LazyProxyOnEnhancedEntityTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.basic.LazyBasicFieldAccessTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.basic.LazyBasicPropertyAccessTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.cache.LazyInCacheTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.group.LazyGroupAccessTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.group.LazyGroupUpdateTestTask;
import org.hibernate.test.bytecode.enhancement.lazy.group.SimpleLazyGroupUpdateTestTask;
@ -119,6 +120,12 @@ public class EnhancerTest extends BaseUnitTestCase {
} );
}
@Test
@TestForIssue( jiraKey = "HHH-11173" )
public void testLazyCache() {
EnhancerTestUtils.runEnhancerTestTask( LazyInCacheTestTask.class );
}
@Test
@TestForIssue( jiraKey = "HHH-10252" )
public void testCascadeDelete() {

View File

@ -0,0 +1,111 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.bytecode.enhancement.lazy.cache;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Type;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.test.bytecode.enhancement.AbstractEnhancerTestTask;
import org.junit.Assert;
import javax.persistence.Basic;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;
/**
* @author Luis Barreiro
*/
public class LazyInCacheTestTask extends AbstractEnhancerTestTask {
public Class<?>[] getAnnotatedClasses() {
return new Class<?>[]{Order.class, Product.class, Tag.class};
}
public void prepare() {
Configuration cfg = new Configuration();
cfg.setProperty( Environment.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" );
prepare( cfg );
}
public void execute() {
EntityManager entityManager = getFactory().createEntityManager();
Order order = new Order();
Product product = new Product();
order.products.add( product );
order.data = "some data".getBytes();
entityManager.getTransaction().begin();
entityManager.persist( product );
entityManager.persist( order );
entityManager.getTransaction().commit();
long orderId = order.id;
entityManager = getFactory().createEntityManager();
order = entityManager.find( Order.class, orderId );
Assert.assertEquals( 1, order.products.size() );
entityManager.close();
}
protected void cleanup() {
}
@Entity
@Cache( usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE )
public static class Order {
@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
long id;
@OneToMany
List<Product> products = new ArrayList<>();
@OneToMany
List<Tag> tags = new ArrayList<>();
@Basic( fetch = FetchType.LAZY )
@Column
@Type( type = "org.hibernate.type.BinaryType" )
private byte[] data;
}
@Entity
public static class Product {
@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
long id;
String name;
}
@Entity
public class Tag {
@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
long id;
String name;
}
}