Open Source Repository

Home /hibernate/hibernate-3.2.4.ga | Repository Home


org/hibernate/type/AnyType.java
//$Id: AnyType.java 7670 2005-07-29 05:36:14Z oneovthafew $
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.Arrays;
import java.util.Map;

import org.dom4j.Node;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.TransientObjectException;
import org.hibernate.engine.CascadeStyle;
import org.hibernate.engine.ForeignKeys;
import org.hibernate.engine.Mapping;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.proxy.HibernateProxyHelper;
import org.hibernate.util.ArrayHelper;

/**
 * Handles "any" mappings and the old deprecated "object" type
 @author Gavin King
 */
public class AnyType extends AbstractType implements AbstractComponentType, AssociationType {

  private final Type identifierType;
  private final Type metaType;

  public AnyType(Type metaType, Type identifierType) {
    this.identifierType = identifierType;
    this.metaType = metaType;
  }

  public AnyType() {
    this(Hibernate.STRING, Hibernate.SERIALIZABLE);
  }

  public Object deepCopy(Object value, EntityMode entityMode, SessionFactoryImplementor factory)
  throws HibernateException {
    return value;
  }
  
  public boolean isMethodOf(Method method) {
    return false;
  }

  public boolean isSame(Object x, Object y, EntityMode entityModethrows HibernateException {
    return x==y;
  }

  public int compare(Object x, Object y, EntityMode entityMode) {
    return 0//TODO: entities CAN be compared, by PK and entity name, fix this!
  }

  public int getColumnSpan(Mapping session)
  throws MappingException {
    return 2;
  }

  public String getName() {
    return "object";
  }

  public boolean isMutable() {
    return false;
  }

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

    throw new UnsupportedOperationException("object is a multicolumn type");
  }

  public Object nullSafeGet(ResultSet rs,  String[] names,  SessionImplementor session,  Object owner)
  throws HibernateException, SQLException {
    return resolveAny(
        (StringmetaType.nullSafeGet(rs, names[0], session, owner),
        (SerializableidentifierType.nullSafeGet(rs, names[1], session, owner),
        session
      );
  }

  public Object hydrate(ResultSet rs,  String[] names,  SessionImplementor session,  Object owner)
  throws HibernateException, SQLException {
    String entityName = (StringmetaType.nullSafeGet(rs, names[0], session, owner);
    Serializable id = (SerializableidentifierType.nullSafeGet(rs, names[1], session, owner);
    return new ObjectTypeCacheEntry(entityName, id);
  }

  public Object resolve(Object value, SessionImplementor session, Object owner)
  throws HibernateException {
    ObjectTypeCacheEntry holder = (ObjectTypeCacheEntryvalue;
    return resolveAny(holder.entityName, holder.id, session);
  }

  public Object semiResolve(Object value, SessionImplementor session, Object owner)
  throws HibernateException {
    throw new UnsupportedOperationException("any mappings may not form part of a property-ref");
  }
  
  private Object resolveAny(String entityName, Serializable id, SessionImplementor session)
  throws HibernateException {
    return entityName==null || id==null ?
        null : session.internalLoadentityName, id, false, false );
  }

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

    Serializable id;
    String entityName;
    if (value==null) {
      id=null;
      entityName=null;
    }
    else {
      entityName = session.bestGuessEntityName(value);
      id = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, value, session);
    }
    
    // metaType is assumed to be single-column type
    if settable==null || settable[0] ) {
      metaType.nullSafeSet(st, entityName, index, session);
    }
    if (settable==null) {
      identifierType.nullSafeSet(st, id, index+1, session);
    }
    else {
      boolean[] idsettable = new booleansettable.length-];
      System.arraycopy(settable, 1, idsettable, 0, idsettable.length);
      identifierType.nullSafeSet(st, id, index+1, idsettable, session);
    }
  }

  public Class getReturnedClass() {
    return Object.class;
  }

  public int[] sqlTypes(Mapping mappingthrows MappingException {
    return ArrayHelper.join(
        metaType.sqlTypes(mapping),
        identifierType.sqlTypes(mapping)
      );
  }

  public void setToXMLNode(Node xml, Object value, SessionFactoryImplementor factory) {
    throw new UnsupportedOperationException("any types cannot be stringified");
  }

  public String toLoggableString(Object value, SessionFactoryImplementor factory
  throws HibernateException {
    //TODO: terrible implementation!
    return value==null ?
        "null" :
        Hibernate.entityHibernateProxyHelper.getClassWithoutInitializingProxy(value) )
            .toLoggableString(value, factory);
  }

  public Object fromXMLNode(Node xml, Mapping factorythrows HibernateException {
    throw new UnsupportedOperationException()//TODO: is this right??
  }

  public static final class ObjectTypeCacheEntry implements Serializable {
    String entityName;
    Serializable id;
    ObjectTypeCacheEntry(String entityName, Serializable id) {
      this.entityName = entityName;
      this.id = id;
    }
  }

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

    ObjectTypeCacheEntry e = (ObjectTypeCacheEntrycached;
    return e==null null : session.internalLoad(e.entityName, e.id, false, false);
  }

  public Serializable disassemble(Object value, SessionImplementor session, Object owner)
  throws HibernateException {
    return value==null ?
      null :
      new ObjectTypeCacheEntry(
            session.bestGuessEntityName(value),
            ForeignKeys.getEntityIdentifierIfNotUnsaved
                session.bestGuessEntityName(value), value, session 
              )
          );
  }

  public boolean isAnyType() {
    return true;
  }

  public Object replace(
      Object original, 
      Object target,
      SessionImplementor session, 
      Object owner, 
      Map copyCache)
  throws HibernateException {
    if (original==null) {
      return null;
    }
    else {
      String entityName = session.bestGuessEntityName(original);
      Serializable id = ForeignKeys.getEntityIdentifierIfNotUnsaved
          entityName, 
          original, 
          session 
        );
      return session.internalLoad
          entityName, 
          id, 
          false, 
          false
        );
    }
  }
  public CascadeStyle getCascadeStyle(int i) {
    return CascadeStyle.NONE;
  }

  public FetchMode getFetchMode(int i) {
    return FetchMode.SELECT;
  }

  private static final String[] PROPERTY_NAMES = new String[] { "class""id" };

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

  public Object getPropertyValue(Object component, int i, SessionImplementor session)
    throws HibernateException {

    return i==?
        session.bestGuessEntityName(component:
        getIdentifier(component, session);
  }

  public Object[] getPropertyValues(Object component, SessionImplementor session)
    throws HibernateException {

    return new Object[] { session.bestGuessEntityName(component), getIdentifier(component, session) };
  }

  private Serializable getIdentifier(Object value, SessionImplementor sessionthrows HibernateException {
    try {
      return ForeignKeys.getEntityIdentifierIfNotUnsavedsession.bestGuessEntityName(value), value, session );
    }
    catch (TransientObjectException toe) {
      return null;
    }
  }

  public Type[] getSubtypes() {
    return new Type[] { metaType, identifierType };
  }

  public void setPropertyValues(Object component, Object[] values, EntityMode entityMode)
    throws HibernateException {

    throw new UnsupportedOperationException();

  }

  public Object[] getPropertyValues(Object component, EntityMode entityMode) {
    throw new UnsupportedOperationException();
  }

  public boolean isComponentType() {
    return true;
  }

  public ForeignKeyDirection getForeignKeyDirection() {
    //return AssociationType.FOREIGN_KEY_TO_PARENT; //this is better but causes a transient object exception...
    return ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT;
  }

  public boolean isAssociationType() {
    return true;
  }

  public boolean useLHSPrimaryKey() {
    return false;
  }

  public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) {
    throw new UnsupportedOperationException("any types do not have a unique referenced persister");
  }

  public boolean isModified(Object old, Object current, boolean[] checkable, SessionImplementor session)
  throws HibernateException {
    if (current==nullreturn old!=null;
    if (old==nullreturn current!=null;
    ObjectTypeCacheEntry holder = (ObjectTypeCacheEntryold;
    boolean[] idcheckable = new boolean[checkable.length-1];
    System.arraycopy(checkable, 1, idcheckable, 0, idcheckable.length);
    return checkable[0&& !holder.entityName.equalssession.bestGuessEntityName(current) ) ) ||
        identifierType.isModified(holder.id, getIdentifier(current, session), idcheckable, session);
  }

  public String getAssociatedEntityName(SessionFactoryImplementor factory)
    throws MappingException {
    throw new UnsupportedOperationException("any types do not have a unique referenced persister");
  }
  
  public boolean[] getPropertyNullability() {
    return null;
  }

  public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
  throws MappingException {
    throw new UnsupportedOperationException();
  }
  
  public boolean isReferenceToPrimaryKey() {
    return true;
  }
  
  public String getRHSUniqueKeyPropertyName() {
    return null;
  }

  public String getLHSPropertyName() {
    return null;
  }

  public boolean isAlwaysDirtyChecked() {
    return false;
  }

  public boolean isEmbeddedInXML() {
    return false;
  }
  
  public boolean[] toColumnNullness(Object value, Mapping mapping) {
    boolean[] result = new booleangetColumnSpan(mapping) ];
    if (value!=nullArrays.fill(result, true);
    return result;
  }

  public boolean isDirty(Object old, Object current, boolean[] checkable, SessionImplementor session
  throws HibernateException {
    //TODO!!!
    return isDirty(old, current, session);
  }

  public boolean isEmbedded() {
    return false;
  }
}