1 /*
2 * Hibernate, Relational Persistence for Idiomatic Java
3 *
4 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
5 * indicated by the @author tags or express copyright attribution
6 * statements applied by the authors. All third-party contributions are
7 * distributed under license by Red Hat Middleware LLC.
8 *
9 * This copyrighted material is made available to anyone wishing to use, modify,
10 * copy, or redistribute it subject to the terms and conditions of the GNU
11 * Lesser General Public License, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this distribution; if not, write to:
20 * Free Software Foundation, Inc.
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02110-1301 USA
23 *
24 */
25 package org.hibernate.tuple.component;
26
27 import java.io.Serializable;
28 import java.lang.reflect.Method;
29
30 import org.hibernate.AssertionFailure;
31 import org.hibernate.HibernateException;
32 import org.hibernate.bytecode.BasicProxyFactory;
33 import org.hibernate.bytecode.ReflectionOptimizer;
34 import org.hibernate.cfg.Environment;
35 import org.hibernate.engine.SessionFactoryImplementor;
36 import org.hibernate.mapping.Component;
37 import org.hibernate.mapping.Property;
38 import org.hibernate.property.BackrefPropertyAccessor;
39 import org.hibernate.property.Getter;
40 import org.hibernate.property.PropertyAccessor;
41 import org.hibernate.property.PropertyAccessorFactory;
42 import org.hibernate.property.Setter;
43 import org.hibernate.tuple.Instantiator;
44 import org.hibernate.tuple.PojoInstantiator;
45 import org.hibernate.util.ReflectHelper;
46
47 /**
48 * A {@link ComponentTuplizer} specific to the pojo entity mode.
49 *
50 * @author Gavin King
51 * @author Steve Ebersole
52 */
53 public class PojoComponentTuplizer extends AbstractComponentTuplizer {
54
55 private final Class componentClass;
56 private ReflectionOptimizer optimizer;
57 private final Getter parentGetter;
58 private final Setter parentSetter;
59
60 public PojoComponentTuplizer(Component component) {
61 super( component );
62
63 this.componentClass = component.getComponentClass();
64
65 String[] getterNames = new String[propertySpan];
66 String[] setterNames = new String[propertySpan];
67 Class[] propTypes = new Class[propertySpan];
68 for ( int i = 0; i < propertySpan; i++ ) {
69 getterNames[i] = getters[i].getMethodName();
70 setterNames[i] = setters[i].getMethodName();
71 propTypes[i] = getters[i].getReturnType();
72 }
73
74 final String parentPropertyName = component.getParentProperty();
75 if ( parentPropertyName == null ) {
76 parentSetter = null;
77 parentGetter = null;
78 }
79 else {
80 PropertyAccessor pa = PropertyAccessorFactory.getPropertyAccessor( null );
81 parentSetter = pa.getSetter( componentClass, parentPropertyName );
82 parentGetter = pa.getGetter( componentClass, parentPropertyName );
83 }
84
85 if ( hasCustomAccessors || !Environment.useReflectionOptimizer() ) {
86 optimizer = null;
87 }
88 else {
89 // TODO: here is why we need to make bytecode provider global :(
90 // TODO : again, fix this after HHH-1907 is complete
91 optimizer = Environment.getBytecodeProvider().getReflectionOptimizer(
92 componentClass, getterNames, setterNames, propTypes
93 );
94 }
95 }
96
97 public Class getMappedClass() {
98 return componentClass;
99 }
100
101 public Object[] getPropertyValues(Object component) throws HibernateException {
102 if ( component == BackrefPropertyAccessor.UNKNOWN ) {
103 return new Object[ propertySpan ];
104 }
105 if ( optimizer != null && optimizer.getAccessOptimizer() != null ) {
106 return optimizer.getAccessOptimizer().getPropertyValues( component );
107 }
108 else {
109 return super.getPropertyValues(component);
110 }
111 }
112
113 public void setPropertyValues(Object component, Object[] values) throws HibernateException {
114 if ( optimizer != null && optimizer.getAccessOptimizer() != null ) {
115 optimizer.getAccessOptimizer().setPropertyValues( component, values );
116 }
117 else {
118 super.setPropertyValues(component, values);
119 }
120
121 }
122
123 public Object getParent(Object component) {
124 return parentGetter.get( component );
125 }
126
127 public boolean hasParentProperty() {
128 return parentGetter!=null;
129 }
130
131 public boolean isMethodOf(Method method) {
132 for ( int i=0; i<propertySpan; i++ ) {
133 final Method getterMethod = getters[i].getMethod();
134 if ( getterMethod!=null && getterMethod.equals(method) ) return true;
135 }
136 return false;
137 }
138
139 public void setParent(Object component, Object parent, SessionFactoryImplementor factory) {
140 parentSetter.set(component, parent, factory);
141 }
142
143 protected Instantiator buildInstantiator(Component component) {
144 if ( component.isEmbedded() && ReflectHelper.isAbstractClass( component.getComponentClass() ) ) {
145 return new ProxiedInstantiator( component );
146 }
147 if ( optimizer == null ) {
148 return new PojoInstantiator( component, null );
149 }
150 else {
151 return new PojoInstantiator( component, optimizer.getInstantiationOptimizer() );
152 }
153 }
154
155 protected Getter buildGetter(Component component, Property prop) {
156 return prop.getGetter( component.getComponentClass() );
157 }
158
159 protected Setter buildSetter(Component component, Property prop) {
160 return prop.getSetter( component.getComponentClass() );
161 }
162
163 private static class ProxiedInstantiator implements Instantiator {
164 private final Class proxiedClass;
165 private final BasicProxyFactory factory;
166
167 public ProxiedInstantiator(Component component) {
168 proxiedClass = component.getComponentClass();
169 if ( proxiedClass.isInterface() ) {
170 factory = Environment.getBytecodeProvider()
171 .getProxyFactoryFactory()
172 .buildBasicProxyFactory( null, new Class[] { proxiedClass } );
173 }
174 else {
175 factory = Environment.getBytecodeProvider()
176 .getProxyFactoryFactory()
177 .buildBasicProxyFactory( proxiedClass, null );
178 }
179 }
180
181 public Object instantiate(Serializable id) {
182 throw new AssertionFailure( "ProxiedInstantiator can only be used to instantiate component" );
183 }
184
185 public Object instantiate() {
186 return factory.getProxy();
187 }
188
189 public boolean isInstance(Object object) {
190 return proxiedClass.isInstance( object );
191 }
192 }
193 }