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;
26
27 import java.lang.reflect.Constructor;
28
29 import org.hibernate.EntityMode;
30 import org.hibernate.mapping.PropertyGeneration;
31 import org.hibernate.engine.IdentifierValue;
32 import org.hibernate.engine.UnsavedValueFactory;
33 import org.hibernate.engine.VersionValue;
34 import org.hibernate.id.IdentifierGenerator;
35 import org.hibernate.mapping.KeyValue;
36 import org.hibernate.mapping.PersistentClass;
37 import org.hibernate.mapping.Property;
38 import org.hibernate.property.Getter;
39 import org.hibernate.property.PropertyAccessor;
40 import org.hibernate.property.PropertyAccessorFactory;
41 import org.hibernate.type.AssociationType;
42 import org.hibernate.type.Type;
43 import org.hibernate.type.VersionType;
44 import org.hibernate.util.ReflectHelper;
45
46 /**
47 * Responsible for generation of runtime metamodel {@link Property} representations.
48 * Makes distinction between identifier, version, and other (standard) properties.
49 *
50 * @author Steve Ebersole
51 */
52 public class PropertyFactory {
53
54 /**
55 * Generates an IdentifierProperty representation of the for a given entity mapping.
56 *
57 * @param mappedEntity The mapping definition of the entity.
58 * @param generator The identifier value generator to use for this identifier.
59 * @return The appropriate IdentifierProperty definition.
60 */
61 public static IdentifierProperty buildIdentifierProperty(PersistentClass mappedEntity, IdentifierGenerator generator) {
62
63 String mappedUnsavedValue = mappedEntity.getIdentifier().getNullValue();
64 Type type = mappedEntity.getIdentifier().getType();
65 Property property = mappedEntity.getIdentifierProperty();
66
67 IdentifierValue unsavedValue = UnsavedValueFactory.getUnsavedIdentifierValue(
68 mappedUnsavedValue,
69 getGetter( property ),
70 type,
71 getConstructor(mappedEntity)
72 );
73
74 if ( property == null ) {
75 // this is a virtual id property...
76 return new IdentifierProperty(
77 type,
78 mappedEntity.hasEmbeddedIdentifier(),
79 mappedEntity.hasIdentifierMapper(),
80 unsavedValue,
81 generator
82 );
83 }
84 else {
85 return new IdentifierProperty(
86 property.getName(),
87 property.getNodeName(),
88 type,
89 mappedEntity.hasEmbeddedIdentifier(),
90 unsavedValue,
91 generator
92 );
93 }
94 }
95
96 /**
97 * Generates a VersionProperty representation for an entity mapping given its
98 * version mapping Property.
99 *
100 * @param property The version mapping Property.
101 * @param lazyAvailable Is property lazy loading currently available.
102 * @return The appropriate VersionProperty definition.
103 */
104 public static VersionProperty buildVersionProperty(Property property, boolean lazyAvailable) {
105 String mappedUnsavedValue = ( (KeyValue) property.getValue() ).getNullValue();
106
107 VersionValue unsavedValue = UnsavedValueFactory.getUnsavedVersionValue(
108 mappedUnsavedValue,
109 getGetter( property ),
110 (VersionType) property.getType(),
111 getConstructor( property.getPersistentClass() )
112 );
113
114 boolean lazy = lazyAvailable && property.isLazy();
115
116 return new VersionProperty(
117 property.getName(),
118 property.getNodeName(),
119 property.getValue().getType(),
120 lazy,
121 property.isInsertable(),
122 property.isUpdateable(),
123 property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
124 property.getGeneration() == PropertyGeneration.ALWAYS,
125 property.isOptional(),
126 property.isUpdateable() && !lazy,
127 property.isOptimisticLocked(),
128 property.getCascadeStyle(),
129 unsavedValue
130 );
131 }
132
133 /**
134 * Generate a "standard" (i.e., non-identifier and non-version) based on the given
135 * mapped property.
136 *
137 * @param property The mapped property.
138 * @param lazyAvailable Is property lazy loading currently available.
139 * @return The appropriate StandardProperty definition.
140 */
141 public static StandardProperty buildStandardProperty(Property property, boolean lazyAvailable) {
142
143 final Type type = property.getValue().getType();
144
145 // we need to dirty check collections, since they can cause an owner
146 // version number increment
147
148 // we need to dirty check many-to-ones with not-found="ignore" in order
149 // to update the cache (not the database), since in this case a null
150 // entity reference can lose information
151
152 boolean alwaysDirtyCheck = type.isAssociationType() &&
153 ( (AssociationType) type ).isAlwaysDirtyChecked();
154
155 return new StandardProperty(
156 property.getName(),
157 property.getNodeName(),
158 type,
159 lazyAvailable && property.isLazy(),
160 property.isInsertable(),
161 property.isUpdateable(),
162 property.getGeneration() == PropertyGeneration.INSERT || property.getGeneration() == PropertyGeneration.ALWAYS,
163 property.getGeneration() == PropertyGeneration.ALWAYS,
164 property.isOptional(),
165 alwaysDirtyCheck || property.isUpdateable(),
166 property.isOptimisticLocked(),
167 property.getCascadeStyle(),
168 property.getValue().getFetchMode()
169 );
170 }
171
172 private static Constructor getConstructor(PersistentClass persistentClass) {
173 if ( persistentClass == null || !persistentClass.hasPojoRepresentation() ) {
174 return null;
175 }
176
177 try {
178 return ReflectHelper.getDefaultConstructor( persistentClass.getMappedClass() );
179 }
180 catch( Throwable t ) {
181 return null;
182 }
183 }
184
185 private static Getter getGetter(Property mappingProperty) {
186 if ( mappingProperty == null || !mappingProperty.getPersistentClass().hasPojoRepresentation() ) {
187 return null;
188 }
189
190 PropertyAccessor pa = PropertyAccessorFactory.getPropertyAccessor( mappingProperty, EntityMode.POJO );
191 return pa.getGetter( mappingProperty.getPersistentClass().getMappedClass(), mappingProperty.getName() );
192 }
193
194 }