org.hibernate.tuple.entity.PojoEntityTuplizer.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.tuple.entity.PojoEntityTuplizer.java

Source

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2008, Red Hat Middleware LLC 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 Middleware LLC.
 *
 * 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.tuple.entity;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.EntityNameResolver;
import org.hibernate.tuple.Instantiator;
import org.hibernate.tuple.PojoInstantiator;
import org.hibernate.bytecode.ReflectionOptimizer;
import org.hibernate.cfg.Environment;
import org.hibernate.classic.Lifecycle;
import org.hibernate.classic.Validatable;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.intercept.FieldInterceptor;
import org.hibernate.intercept.FieldInterceptionHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.mapping.Subclass;
import org.hibernate.property.Getter;
import org.hibernate.property.Setter;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.ProxyFactory;
import org.hibernate.type.AbstractComponentType;
import org.hibernate.util.ReflectHelper;

/**
 * An {@link EntityTuplizer} specific to the pojo entity mode.
 *
 * @author Steve Ebersole
 * @author Gavin King
 */
public class PojoEntityTuplizer extends AbstractEntityTuplizer {

    static final Log log = LogFactory.getLog(PojoEntityTuplizer.class);

    private final Class mappedClass;
    private final Class proxyInterface;
    private final boolean lifecycleImplementor;
    private final boolean validatableImplementor;
    private final Set lazyPropertyNames = new HashSet();
    private final ReflectionOptimizer optimizer;

    public PojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
        super(entityMetamodel, mappedEntity);
        this.mappedClass = mappedEntity.getMappedClass();
        this.proxyInterface = mappedEntity.getProxyInterface();
        this.lifecycleImplementor = Lifecycle.class.isAssignableFrom(mappedClass);
        this.validatableImplementor = Validatable.class.isAssignableFrom(mappedClass);

        Iterator iter = mappedEntity.getPropertyClosureIterator();
        while (iter.hasNext()) {
            Property property = (Property) iter.next();
            if (property.isLazy()) {
                lazyPropertyNames.add(property.getName());
            }
        }

        String[] getterNames = new String[propertySpan];
        String[] setterNames = new String[propertySpan];
        Class[] propTypes = new Class[propertySpan];
        for (int i = 0; i < propertySpan; i++) {
            getterNames[i] = getters[i].getMethodName();
            setterNames[i] = setters[i].getMethodName();
            propTypes[i] = getters[i].getReturnType();
        }

        if (hasCustomAccessors || !Environment.useReflectionOptimizer()) {
            optimizer = null;
        } else {
            // todo : YUCK!!!
            optimizer = Environment.getBytecodeProvider().getReflectionOptimizer(mappedClass, getterNames,
                    setterNames, propTypes);
            //         optimizer = getFactory().getSettings().getBytecodeProvider().getReflectionOptimizer(
            //               mappedClass, getterNames, setterNames, propTypes
            //         );
        }

    }

    /**
     * {@inheritDoc}
     */
    protected ProxyFactory buildProxyFactory(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
        // determine the id getter and setter methods from the proxy interface (if any)
        // determine all interfaces needed by the resulting proxy
        HashSet proxyInterfaces = new HashSet();
        proxyInterfaces.add(HibernateProxy.class);

        Class mappedClass = persistentClass.getMappedClass();
        Class proxyInterface = persistentClass.getProxyInterface();

        if (proxyInterface != null && !mappedClass.equals(proxyInterface)) {
            if (!proxyInterface.isInterface()) {
                throw new MappingException(
                        "proxy must be either an interface, or the class itself: " + getEntityName());
            }
            proxyInterfaces.add(proxyInterface);
        }

        if (mappedClass.isInterface()) {
            proxyInterfaces.add(mappedClass);
        }

        Iterator iter = persistentClass.getSubclassIterator();
        while (iter.hasNext()) {
            Subclass subclass = (Subclass) iter.next();
            Class subclassProxy = subclass.getProxyInterface();
            Class subclassClass = subclass.getMappedClass();
            if (subclassProxy != null && !subclassClass.equals(subclassProxy)) {
                if (!proxyInterface.isInterface()) {
                    throw new MappingException(
                            "proxy must be either an interface, or the class itself: " + subclass.getEntityName());
                }
                proxyInterfaces.add(subclassProxy);
            }
        }

        Iterator properties = persistentClass.getPropertyIterator();
        Class clazz = persistentClass.getMappedClass();
        while (properties.hasNext()) {
            Property property = (Property) properties.next();
            Method method = property.getGetter(clazz).getMethod();
            if (method != null && Modifier.isFinal(method.getModifiers())) {
                log.error("Getters of lazy classes cannot be final: " + persistentClass.getEntityName() + "."
                        + property.getName());
            }
            method = property.getSetter(clazz).getMethod();
            if (method != null && Modifier.isFinal(method.getModifiers())) {
                log.error("Setters of lazy classes cannot be final: " + persistentClass.getEntityName() + "."
                        + property.getName());
            }
        }

        Method idGetterMethod = idGetter == null ? null : idGetter.getMethod();
        Method idSetterMethod = idSetter == null ? null : idSetter.getMethod();

        Method proxyGetIdentifierMethod = idGetterMethod == null || proxyInterface == null ? null
                : ReflectHelper.getMethod(proxyInterface, idGetterMethod);
        Method proxySetIdentifierMethod = idSetterMethod == null || proxyInterface == null ? null
                : ReflectHelper.getMethod(proxyInterface, idSetterMethod);

        ProxyFactory pf = buildProxyFactoryInternal(persistentClass, idGetter, idSetter);
        try {
            pf.postInstantiate(getEntityName(), mappedClass, proxyInterfaces, proxyGetIdentifierMethod,
                    proxySetIdentifierMethod,
                    persistentClass.hasEmbeddedIdentifier()
                            ? (AbstractComponentType) persistentClass.getIdentifier().getType()
                            : null);
        } catch (HibernateException he) {
            log.warn("could not create proxy factory for:" + getEntityName(), he);
            pf = null;
        }
        return pf;
    }

    protected ProxyFactory buildProxyFactoryInternal(PersistentClass persistentClass, Getter idGetter,
            Setter idSetter) {
        // TODO : YUCK!!!  fix after HHH-1907 is complete
        return Environment.getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
        //      return getFactory().getSettings().getBytecodeProvider().getProxyFactoryFactory().buildProxyFactory();
    }

    /**
     * {@inheritDoc}
     */
    protected Instantiator buildInstantiator(PersistentClass persistentClass) {
        if (optimizer == null) {
            return new PojoInstantiator(persistentClass, null);
        } else {
            return new PojoInstantiator(persistentClass, optimizer.getInstantiationOptimizer());
        }
    }

    /**
     * {@inheritDoc}
     */
    public void setPropertyValues(Object entity, Object[] values) throws HibernateException {
        if (!getEntityMetamodel().hasLazyProperties() && optimizer != null
                && optimizer.getAccessOptimizer() != null) {
            setPropertyValuesWithOptimizer(entity, values);
        } else {
            super.setPropertyValues(entity, values);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Object[] getPropertyValues(Object entity) throws HibernateException {
        if (shouldGetAllProperties(entity) && optimizer != null && optimizer.getAccessOptimizer() != null) {
            return getPropertyValuesWithOptimizer(entity);
        } else {
            return super.getPropertyValues(entity);
        }
    }

    /**
     * {@inheritDoc}
     */
    public Object[] getPropertyValuesToInsert(Object entity, Map mergeMap, SessionImplementor session)
            throws HibernateException {
        if (shouldGetAllProperties(entity) && optimizer != null && optimizer.getAccessOptimizer() != null) {
            return getPropertyValuesWithOptimizer(entity);
        } else {
            return super.getPropertyValuesToInsert(entity, mergeMap, session);
        }
    }

    protected void setPropertyValuesWithOptimizer(Object object, Object[] values) {
        optimizer.getAccessOptimizer().setPropertyValues(object, values);
    }

    protected Object[] getPropertyValuesWithOptimizer(Object object) {
        return optimizer.getAccessOptimizer().getPropertyValues(object);
    }

    /**
     * {@inheritDoc}
     */
    public EntityMode getEntityMode() {
        return EntityMode.POJO;
    }

    /**
     * {@inheritDoc}
     */
    public Class getMappedClass() {
        return mappedClass;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isLifecycleImplementor() {
        return lifecycleImplementor;
    }

    /**
     * {@inheritDoc}
     */
    public boolean isValidatableImplementor() {
        return validatableImplementor;
    }

    /**
     * {@inheritDoc}
     */
    protected Getter buildPropertyGetter(Property mappedProperty, PersistentClass mappedEntity) {
        return mappedProperty.getGetter(mappedEntity.getMappedClass());
    }

    /**
     * {@inheritDoc}
     */
    protected Setter buildPropertySetter(Property mappedProperty, PersistentClass mappedEntity) {
        return mappedProperty.getSetter(mappedEntity.getMappedClass());
    }

    /**
     * {@inheritDoc}
     */
    public Class getConcreteProxyClass() {
        return proxyInterface;
    }

    //TODO: need to make the majority of this functionality into a top-level support class for custom impl support

    /**
     * {@inheritDoc}
     */
    public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
        if (isInstrumented()) {
            Set lazyProps = lazyPropertiesAreUnfetched && getEntityMetamodel().hasLazyProperties()
                    ? lazyPropertyNames
                    : null;
            //TODO: if we support multiple fetch groups, we would need
            //      to clone the set of lazy properties!
            FieldInterceptionHelper.injectFieldInterceptor(entity, getEntityName(), lazyProps, session);
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean hasUninitializedLazyProperties(Object entity) {
        if (getEntityMetamodel().hasLazyProperties()) {
            FieldInterceptor callback = FieldInterceptionHelper.extractFieldInterceptor(entity);
            return callback != null && !callback.isInitialized();
        } else {
            return false;
        }
    }

    /**
     * {@inheritDoc}
     */
    public boolean isInstrumented() {
        return FieldInterceptionHelper.isInstrumented(getMappedClass());
    }

    /**
     * {@inheritDoc}
     */
    public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) {
        final Class concreteEntityClass = entityInstance.getClass();
        if (concreteEntityClass == getMappedClass()) {
            return getEntityName();
        } else {
            String entityName = getEntityMetamodel().findEntityNameByEntityClass(concreteEntityClass);
            if (entityName == null) {
                throw new HibernateException(
                        "Unable to resolve entity name from Class [" + concreteEntityClass.getName() + "]"
                                + " expected instance/subclass of [" + getEntityName() + "]");
            }
            return entityName;
        }
    }

    /**
     * {@inheritDoc}
     */
    public EntityNameResolver[] getEntityNameResolvers() {
        return null;
    }
}