you should probably use a UserType to code such application semantic.

Pablo Nussembaum wrote:
Hi,
I made a simple modification in the ComponentType class to consider null component equals to a components with all his properties nulls.
   I do this to address 2 problems I have:

  1. For simplicity in all entities, when a components is null the
     getters builds a new instance and then returning it. But with this
     pattern hibernate detects this entities dirty and generates
     updates to the db that aren't need.
  2. I have a very long process where I traverse a long dataset make
     some computations and generates very few result.  This process
     always generates OutofMemory exception because hibernate detects
     to many dirty entities (one solution it to flush the session
     often, but I don't want to update the entity and the process with
     the spurious updates is slower)

---------------------------------------
Some code to explain better:

/**
* return the properties' values if the components != null, or and array of null values.
*/
private Object[] getPropertyValuesArray(Object component, EntityMode entityMode) {
   if (component == null) {
       return new Object[propertyTypes.length];
   } else {
       return getPropertyValues(component, entityMode);
   }
}

/**
* And somethig similar for isDirty, isSame
*/
public boolean isEqual(Object x, Object y, EntityMode entityMode) throws HibernateException {
       if ( x == y ) return true;
       //if ( x == null || y == null ) return false;
       Object[] xvalues = getPropertyValuesArray(x, entityMode);
       Object[] yvalues = getPropertyValuesArray(y, entityMode);
       for ( int i = 0; i < propertySpan; i++ ) {
if ( !propertyTypes[i].isEqual( xvalues[i], yvalues[i], entityMode ) ) return false;
       }
       return true;
   }

-----------------------------------

Regars,
------------------------------------------------------------------------

//$Id: ComponentType.java,v 1.37 2005/07/29 05:36:14 oneovthafew Exp $
package org.hibernate.type;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.Element;
import org.dom4j.Node;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.Mapping;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.tuple.ComponentTuplizer;
import org.hibernate.tuple.TuplizerLookup;
import org.hibernate.util.ArrayHelper;
import org.hibernate.util.StringHelper;

/**
 * Handles "component" mappings
 *
 * @author Gavin King
 */
public class ComponentType extends AbstractType implements 
AbstractComponentType {

        private final Type[] propertyTypes;
        private final String[] propertyNames;
        private final boolean[] propertyNullability;
        protected final int propertySpan;
        private final CascadeStyle[] cascade;
        private final FetchMode[] joinedFetch;
        private final boolean isKey;
        
        protected TuplizerLookup tuplizers;

        public int[] sqlTypes(Mapping mapping) throws MappingException {
                //Not called at runtime so doesn't matter if its slow :)
                int[] sqlTypes = new int[getColumnSpan( mapping )];
                int n = 0;
                for ( int i = 0; i < propertySpan; i++ ) {
                        int[] subtypes = propertyTypes[i].sqlTypes( mapping );
                        for ( int j = 0; j < subtypes.length; j++ ) {
                                sqlTypes[n++] = subtypes[j];
                        }
                }
                return sqlTypes;
        }

        public int getColumnSpan(Mapping mapping) throws MappingException {
                int span = 0;
                for ( int i = 0; i < propertySpan; i++ ) {
                        span += propertyTypes[i].getColumnSpan( mapping );
                }
                return span;
        }

        public ComponentType(
                        final String[] propertyNames,
                        final Type[] propertyTypes,
                        final boolean[] nullabilities,
                        final FetchMode[] joinedFetch,
                        final CascadeStyle[] cascade,
                        final boolean key,
final TuplizerLookup tuplizers) throws MappingException {

                this.propertyTypes = propertyTypes;
                this.propertyNullability = nullabilities;
                this.propertyNames = propertyNames;
                this.cascade = cascade;
                this.joinedFetch = joinedFetch;
                isKey = key;
                propertySpan = propertyTypes.length;
                this.tuplizers = tuplizers;
        }

        public final boolean isComponentType() {
                return true;
        }

        public Class getReturnedClass() {
                return tuplizers.getTuplizer(EntityMode.POJO).getMappedClass(); 
//TODO
        }

        private Object[] getPropertyValuesArray(Object component, EntityMode 
entityMode) {
                if (component == null) {
                        return new Object[propertyTypes.length];
                } else {
                        return getPropertyValues(component, entityMode);
                }
        }
        
        public boolean isSame(Object x, Object y, EntityMode entityMode) throws 
HibernateException {
                if ( x == y ) return true;
                Object[] xvalues = getPropertyValuesArray(y, entityMode);
                Object[] yvalues = getPropertyValuesArray(y, entityMode);
                for ( int i = 0; i < propertySpan; i++ ) {
                        if ( !propertyTypes[i].isSame( xvalues[i], yvalues[i], 
entityMode ) ) {
                                return false;
                        }
                }
                return true;
        }

public boolean isEqual(Object x, Object y, EntityMode entityMode) throws HibernateException {
                if ( x == y ) return true;
                //if ( x == null || y == null ) return false;
                Object[] xvalues = getPropertyValuesArray(x, entityMode);
                Object[] yvalues = getPropertyValuesArray(y, entityMode);
                for ( int i = 0; i < propertySpan; i++ ) {
                        if ( !propertyTypes[i].isEqual( xvalues[i], yvalues[i], 
entityMode ) ) return false;
                }
                return true;
        }

public boolean isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory) throws HibernateException {
                if ( x == y ) return true;
                //if ( x == null || y == null ) return false;
                Object[] xvalues = getPropertyValuesArray(x, entityMode);
                Object[] yvalues = getPropertyValuesArray(y, entityMode);
                for ( int i = 0; i < propertySpan; i++ ) {
                        if ( !propertyTypes[i].isEqual( xvalues[i], yvalues[i], 
entityMode, factory ) ) return false;
                }
                return true;
        }

        public int compare(Object x, Object y, EntityMode entityMode) {
                if ( x == y ) return 0;
                Object[] xvalues = getPropertyValuesArray(x, entityMode);
                Object[] yvalues = getPropertyValuesArray(y, entityMode);
                for ( int i = 0; i < propertySpan; i++ ) {
                        int propertyCompare = propertyTypes[i].compare( 
xvalues[i], yvalues[i], entityMode );
                        if ( propertyCompare != 0 ) return propertyCompare;
                }
                return 0;
        }
        
        public boolean isMethodOf(Method method) {
                return false;
        }

        public int getHashCode(Object x, EntityMode entityMode) {
                int result = 17;
                Object[] values = getPropertyValues(x, entityMode);
                for ( int i = 0; i < propertySpan; i++ ) {
                        Object y = values[i];
                        result *= 37;
                        if ( y != null ) result += 
propertyTypes[i].getHashCode( y, entityMode );
                }
                return result;
        }

        public int getHashCode(Object x, EntityMode entityMode, 
SessionFactoryImplementor factory) {
                int result = 17;
                Object[] values = getPropertyValues(x, entityMode);
                for ( int i = 0; i < propertySpan; i++ ) {
                        Object y = values[i];
                        result *= 37;
                        if ( y != null ) result += 
propertyTypes[i].getHashCode( y, entityMode, factory );
                }
                return result;
        }

public boolean isDirty(Object x, Object y, SessionImplementor session) throws HibernateException {
                if ( x == y ) return false;
                //if ( x == null || y == null ) return true;
                EntityMode entityMode = session.getEntityMode();
                Object[] xvalues = getPropertyValues(x, entityMode);
                Object[] yvalues = getPropertyValues(y, entityMode);
                for ( int i = 0; i < xvalues.length; i++ ) {
                        if ( propertyTypes[i].isDirty( xvalues[i], yvalues[i], 
session ) ) return true;
                }
                return false;
        }

public boolean isDirty(Object x, Object y, boolean[] checkable, SessionImplementor session) throws HibernateException {
                if ( x == y ) return false;
                //if ( x == null || y == null ) return true;
                EntityMode entityMode = session.getEntityMode();
                Object[] xvalues = getPropertyValuesArray(x, entityMode);
                Object[] yvalues = getPropertyValuesArray(y, entityMode);
                int loc = 0;
                for ( int i = 0; i < xvalues.length; i++ ) {
                        int len = propertyTypes[i].getColumnSpan( 
session.getFactory() );
                        if (len<=1) {
final boolean dirty = ( len==0 || checkable[loc] ) && propertyTypes[i].isDirty( xvalues[i], yvalues[i], session );
                                if ( dirty ) return true;
                        }
                        else {
                                boolean[] subcheckable = new boolean[len];
                                System.arraycopy(checkable, loc, subcheckable, 
0, len);
                                final boolean dirty = propertyTypes[i].isDirty( 
xvalues[i], yvalues[i], subcheckable, session );
                                if ( dirty ) return true;
                        }
                        loc += len;
                }
                return false;
        }

        public boolean isModified(Object old, Object current, boolean[] 
checkable, SessionImplementor session)
                        throws HibernateException {
                
                if (old == null && current == null) return false;
                if (current == null) return true;
                Object[] currentValues;
                Object[] oldValues;
                if (old == null && current != null) {
                        currentValues = getPropertyValues(current, session);
                        oldValues = new Object[currentValues.length];
                } else {
                        currentValues = getPropertyValues( current, session );
                        oldValues = ( Object[] ) old;
                }
                int loc = 0;
                for ( int i = 0; i < currentValues.length; i++ ) {
                        int len = propertyTypes[i].getColumnSpan( 
session.getFactory() );
                        boolean[] subcheckable = new boolean[len];
                        System.arraycopy(checkable, loc, subcheckable, 0, len);
                        if ( propertyTypes[i].isModified( oldValues[i], 
currentValues[i], subcheckable, session ) ) {
                                return true;
                        }
                        loc += len;
                }
                return false;
                
        }

        public Object nullSafeGet(ResultSet rs, String[] names, 
SessionImplementor session, Object owner)
                        throws HibernateException, SQLException {
                return resolve( hydrate( rs, names, session, owner ), session, 
owner );
        }

        public void nullSafeSet(PreparedStatement st, Object value, int begin, 
SessionImplementor session)
        throws HibernateException, SQLException {

                Object[] subvalues = nullSafeGetValues( value, 
session.getEntityMode() );

                for ( int i = 0; i < propertySpan; i++ ) {
                        propertyTypes[i].nullSafeSet( st, subvalues[i], begin, 
session );
                        begin += propertyTypes[i].getColumnSpan( 
session.getFactory() );
                }
        }

        public void nullSafeSet(
PreparedStatement st, Object value, int begin, boolean[] settable, SessionImplementor session)
        throws HibernateException, SQLException {

                Object[] subvalues = nullSafeGetValues( value, 
session.getEntityMode() );
                
                int loc = 0;
                for ( int i = 0; i < propertySpan; i++ ) {
                        int len = propertyTypes[i].getColumnSpan( 
session.getFactory() );
                        if (len==0) {
                                //noop
                        }
                        else if (len==1) {
                                if ( settable[loc] ) {
                                        propertyTypes[i].nullSafeSet( st, 
subvalues[i], begin, session );
                                        begin++;
                                }
                        }
                        else {
                                boolean[] subsettable = new boolean[len];
                                System.arraycopy(settable, loc, subsettable, 0, 
len);
                                propertyTypes[i].nullSafeSet( st, subvalues[i], 
begin, subsettable, session );
                                begin += ArrayHelper.countTrue(subsettable);
                        }
                        loc += len;
                }
        }

        private Object[] nullSafeGetValues(Object value, EntityMode entityMode) 
throws HibernateException {
                if ( value == null ) {
                        return new Object[propertySpan];
                }
                else {
                        return getPropertyValues( value, entityMode );
                }
        }

        public Object nullSafeGet(ResultSet rs, String name, SessionImplementor 
session, Object owner)
                        throws HibernateException, SQLException {

                return nullSafeGet( rs, new String[]{name}, session, owner );
        }

        public Object getPropertyValue(Object component, int i, 
SessionImplementor session)
                        throws HibernateException {
                return getPropertyValue( component, i, session.getEntityMode() 
);
        }

        public Object getPropertyValue(Object component, int i, EntityMode 
entityMode)
        throws HibernateException {
                return tuplizers.getTuplizer(entityMode).getPropertyValue( 
component, i );
        }

        public Object[] getPropertyValues(Object component, SessionImplementor 
session)
                        throws HibernateException {
                return getPropertyValues( component, session.getEntityMode() );
        }

public Object[] getPropertyValues(Object component, EntityMode entityMode) throws HibernateException {
                return 
tuplizers.getTuplizer(entityMode).getPropertyValues(component);
        }

public void setPropertyValues(Object component, Object[] values, EntityMode entityMode) throws HibernateException {
                tuplizers.getTuplizer(entityMode).setPropertyValues(component, 
values);
        }

        public Type[] getSubtypes() {
                return propertyTypes;
        }

        public String getName() {
                return "component" + ArrayHelper.toString(propertyNames);
        }

        public String toLoggableString(Object value, SessionFactoryImplementor 
factory)
                        throws HibernateException {
                if ( value == null ) return "null";
                Map result = new HashMap();
                EntityMode entityMode = tuplizers.guessEntityMode(value);
                if (entityMode==null) {
                        throw new ClassCastException( 
value.getClass().getName() );
                }
                Object[] values = getPropertyValues( value, entityMode );
                for ( int i = 0; i < propertyTypes.length; i++ ) {
                        result.put( propertyNames[i], 
propertyTypes[i].toLoggableString( values[i], factory ) );
                }
                return StringHelper.unqualify( getName() ) + result.toString();
        }

        public String[] getPropertyNames() {
                return propertyNames;
        }

public Object deepCopy(Object component, EntityMode entityMode, SessionFactoryImplementor factory) throws HibernateException {
                if ( component == null ) return null;

                Object[] values = getPropertyValues( component, entityMode );
                for ( int i = 0; i < propertySpan; i++ ) {
                        values[i] = propertyTypes[i].deepCopy( values[i], 
entityMode, factory );
                }

                Object result = instantiate(entityMode);
                setPropertyValues( result, values, entityMode );

                //not absolutely necessary, but helps for some
                //equals()/hashCode() implementations
                ComponentTuplizer ct = (ComponentTuplizer) 
tuplizers.getTuplizer(entityMode);
                if ( ct.hasParentProperty() ) {
                        ct.setParent( result, ct.getParent(component), factory 
);
                }

                return result;
        }

        public Object replace(
                        Object original,
                        Object target,
                        SessionImplementor session,
Object owner, Map copyCache)
                throws HibernateException {

                if ( original == null ) return null;
                //if ( original == target ) return target;

                final Object result = target == null ?
                                instantiate( owner, session ) :
                                target;
                                
                final EntityMode entityMode = session.getEntityMode();
Object[] values = TypeFactory.replace( getPropertyValues( original, entityMode ),
                                getPropertyValues( result, entityMode ),
                                propertyTypes,
                                session,
owner, copyCache
                        );

                setPropertyValues( result, values, entityMode );
                return result;
        }

        public Object replace(
                        Object original,
                        Object target,
                        SessionImplementor session,
Object owner, Map copyCache,
                        ForeignKeyDirection foreignKeyDirection)
                throws HibernateException {

                if ( original == null ) return null;
                //if ( original == target ) return target;

                final Object result = target == null ?
                                instantiate( owner, session ) :
                                target;
                                
                final EntityMode entityMode = session.getEntityMode();
Object[] values = TypeFactory.replace( getPropertyValues( original, entityMode ),
                                getPropertyValues( result, entityMode ),
                                propertyTypes,
                                session,
owner, copyCache,
                                foreignKeyDirection
                        );

                setPropertyValues( result, values, entityMode );
                return result;
        }

        /**
         * This method does not populate the component parent
         */
        public Object instantiate(EntityMode entityMode) throws 
HibernateException {
                return tuplizers.getTuplizer(entityMode).instantiate();
        }

        public Object instantiate(Object parent, SessionImplementor session)
        throws HibernateException {
                
                Object result = instantiate( session.getEntityMode() );

                ComponentTuplizer ct = (ComponentTuplizer) 
tuplizers.getTuplizer( session.getEntityMode() );
                if ( ct.hasParentProperty() && parent != null ) {
ct.setParent( result, session.getPersistenceContext().proxyFor( parent ), session.getFactory() );
                }
                
                return result;
        }

        public CascadeStyle getCascadeStyle(int i) {
                return cascade[i];
        }

        public boolean isMutable() {
                return true;
        }

        public Serializable disassemble(Object value, SessionImplementor 
session, Object owner)
                        throws HibernateException {

                if ( value == null ) {
                        return null;
                }
                else {
                        Object[] values = getPropertyValues( value, 
session.getEntityMode() );
                        for ( int i = 0; i < propertyTypes.length; i++ ) {
                                values[i] = propertyTypes[i].disassemble( 
values[i], session, owner );
                        }
                        return values;
                }
        }

        public Object assemble(Serializable object, SessionImplementor session, 
Object owner)
                        throws HibernateException {

                if ( object == null ) {
                        return null;
                }
                else {
                        Object[] values = (Object[]) object;
                        Object[] assembled = new Object[values.length];
                        for ( int i = 0; i < propertyTypes.length; i++ ) {
                                assembled[i] = propertyTypes[i].assemble( ( 
Serializable ) values[i], session, owner );
                        }
                        Object result = instantiate( owner, session );
                        setPropertyValues( result, assembled, 
session.getEntityMode() );
                        return result;
                }
        }

        public FetchMode getFetchMode(int i) {
                return joinedFetch[i];
        }

        public Object hydrate(
                        final ResultSet rs,
                        final String[] names,
                        final SessionImplementor session,
                        final Object owner)
        throws HibernateException, SQLException {

                int begin = 0;
                boolean notNull = false;
                Object[] values = new Object[propertySpan];
                for ( int i = 0; i < propertySpan; i++ ) {
                        int length = propertyTypes[i].getColumnSpan( 
session.getFactory() );
                        String[] range = ArrayHelper.slice( names, begin, 
length ); //cache this
                        Object val = propertyTypes[i].hydrate( rs, range, 
session, owner );
                        if ( val == null ) {
                                if (isKey) return null; //different nullability 
rules for pk/fk
                        }
                        else {
                                notNull = true;
                        }
                        values[i] = val;
                        begin += length;
                }

                return notNull ? values : null;
        }

        public Object resolve(Object value, SessionImplementor session, Object 
owner)
                throws HibernateException {

                if ( value != null ) {
                        Object result = instantiate( owner, session );
                        Object[] values = ( Object[] ) value;
                        Object[] resolvedValues = new Object[values.length]; 
//only really need new array during semiresolve!
                        for ( int i = 0; i < values.length; i++ ) {
                                resolvedValues[i] = propertyTypes[i].resolve( 
values[i], session, owner );
                        }
                        setPropertyValues( result, resolvedValues, 
session.getEntityMode() );
                        return result;
                }
                else {
                        return null;
                }
        }

        public Object semiResolve(Object value, SessionImplementor session, 
Object owner)
                        throws HibernateException {
                //note that this implementation is kinda broken
                //for components with many-to-one associations
                return resolve( value, session, owner );
        }

        public boolean[] getPropertyNullability() {
                return propertyNullability;
        }

        public boolean isXMLElement() {
                return true;
        }

        public Object fromXMLNode(Node xml, Mapping factory) throws 
HibernateException {
                return xml;
        }

        public void setToXMLNode(Node node, Object value, 
SessionFactoryImplementor factory) throws HibernateException {
                replaceNode( node, (Element) value );
        }

        public boolean[] toColumnNullness(Object value, Mapping mapping) {
                boolean[] result = new boolean[ getColumnSpan(mapping) ];
                if (value==null) return result;
                Object[] values = getPropertyValues(value, EntityMode.POJO); 
//TODO!!!!!!!
                int loc = 0;
                for ( int i=0; i<propertyTypes.length; i++ ) {
                        boolean[] propertyNullness = 
propertyTypes[i].toColumnNullness( values[i], mapping );
                        System.arraycopy(propertyNullness, 0, result, loc, 
propertyNullness.length);
                        loc += propertyNullness.length;
                }
                return result;
        }
        
        public boolean isEmbedded() {
                return false;
        }

}



-------------------------------------------------------
This SF.Net email is sponsored by xPML, a groundbreaking scripting language
that extends applications into web and mobile media. Attend the live webcast
and join the prime developer group breaking into this new coding territory!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
_______________________________________________
hibernate-devel mailing list
hibernate-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/hibernate-devel

Reply via email to