/* * 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.tuple.component; import java.io.Serializable; import java.lang.reflect.Method; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.bytecode.spi.BasicProxyFactory; import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.cfg.Environment; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.mapping.Component; import org.hibernate.mapping.Property; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl; import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.Setter; import org.hibernate.tuple.Instantiator; import org.hibernate.tuple.PojoInstantiator; /** * A {@link ComponentTuplizer} specific to the pojo entity mode. * * @author Gavin King * @author Steve Ebersole */ public class PojoComponentTuplizer extends AbstractComponentTuplizer { private Class componentClass; private ReflectionOptimizer optimizer; private final Getter parentGetter; private final Setter parentSetter; public PojoComponentTuplizer(Component component) { super( component ); 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(); } final String parentPropertyName = component.getParentProperty(); if ( parentPropertyName == null ) { parentSetter = null; parentGetter = null; } else { final PropertyAccess propertyAccess = PropertyAccessStrategyBasicImpl.INSTANCE.buildPropertyAccess( componentClass, parentPropertyName ); parentSetter = propertyAccess.getSetter(); parentGetter = propertyAccess.getGetter(); } if ( hasCustomAccessors || !Environment.useReflectionOptimizer() ) { optimizer = null; } else { // TODO: here is why we need to make bytecode provider global :( // TODO : again, fix this after HHH-1907 is complete optimizer = Environment.getBytecodeProvider().getReflectionOptimizer( componentClass, getterNames, setterNames, propTypes ); } } public Class getMappedClass() { return componentClass; } public Object[] getPropertyValues(Object component) throws HibernateException { if ( component == PropertyAccessStrategyBackRefImpl.UNKNOWN ) { return new Object[propertySpan]; } else if ( optimizer != null && optimizer.getAccessOptimizer() != null ) { return optimizer.getAccessOptimizer().getPropertyValues( component ); } else { return super.getPropertyValues( component ); } } public void setPropertyValues(Object component, Object[] values) throws HibernateException { if ( optimizer != null && optimizer.getAccessOptimizer() != null ) { optimizer.getAccessOptimizer().setPropertyValues( component, values ); } else { super.setPropertyValues( component, values ); } } public Object getParent(Object component) { return parentGetter.get( component ); } public boolean hasParentProperty() { return parentGetter != null; } public boolean isMethodOf(Method method) { for ( int i = 0; i < propertySpan; i++ ) { final Method getterMethod = getters[i].getMethod(); if ( getterMethod != null && getterMethod.equals( method ) ) { return true; } } return false; } public void setParent(Object component, Object parent, SessionFactoryImplementor factory) { parentSetter.set( component, parent, factory ); } protected Instantiator buildInstantiator(Component component) { if ( component.isEmbedded() && ReflectHelper.isAbstractClass( this.componentClass ) ) { return new ProxiedInstantiator( this.componentClass ); } if ( optimizer == null ) { return new PojoInstantiator( this.componentClass, null ); } else { return new PojoInstantiator( this.componentClass, optimizer.getInstantiationOptimizer() ); } } protected Getter buildGetter(Component component, Property prop) { return prop.getGetter( this.componentClass ); } protected Setter buildSetter(Component component, Property prop) { return prop.getSetter( this.componentClass ); } @Override protected void setComponentClass(Component component) { this.componentClass = component.getComponentClass(); } private static class ProxiedInstantiator implements Instantiator { private final Class proxiedClass; private final BasicProxyFactory factory; public ProxiedInstantiator(Class componentClass) { proxiedClass = componentClass; if ( proxiedClass.isInterface() ) { factory = Environment.getBytecodeProvider() .getProxyFactoryFactory() .buildBasicProxyFactory( null, new Class[] { proxiedClass } ); } else { factory = Environment.getBytecodeProvider() .getProxyFactoryFactory() .buildBasicProxyFactory( proxiedClass, null ); } } public Object instantiate(Serializable id) { throw new AssertionFailure( "ProxiedInstantiator can only be used to instantiate component" ); } public Object instantiate() { return factory.getProxy(); } public boolean isInstance(Object object) { return proxiedClass.isInstance( object ); } } }