Project

General

Profile

« Previous | Next » 

Revision 06abbea1

Added by Cherian Mathew over 8 years ago

Fix classloading priority of patched hibernate class

View differences:

cdmlib-persistence/src/main/java/org/hibernate/type/EntityType.java
53 53
 * Note : This class overrides the Hibernate EntityType class to provide a
54 54
 * workaround for problem in method 'replace'. Need to check if
55 55
 * this problem is fixed in later versions of hibernate or open a bug report
56
 * with a patch.
56
 * with a patch. This overriding class appears both in the 'cdmlib-persistence'
57
 * and the 'cdmlib-remote-webapp' projects to ensure that it is loaded with
58
 * priority before the original class.
57 59
 *
58 60
 * @author Gavin King
59 61
 */
cdmlib-remote-webapp/src/main/java/org/hibernate/type/EntityType.java
1
/*
2
 * Hibernate, Relational Persistence for Idiomatic Java
3
 *
4
 * Copyright (c) 2010, Red Hat Inc. 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 Inc.
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
package org.hibernate.type;
25

  
26
import java.io.Serializable;
27
import java.sql.ResultSet;
28
import java.sql.SQLException;
29
import java.util.Map;
30

  
31
import org.dom4j.Element;
32
import org.dom4j.Node;
33
import org.hibernate.AssertionFailure;
34
import org.hibernate.EntityMode;
35
import org.hibernate.HibernateException;
36
import org.hibernate.MappingException;
37
import org.hibernate.engine.internal.ForeignKeys;
38
import org.hibernate.engine.spi.EntityUniqueKey;
39
import org.hibernate.engine.spi.Mapping;
40
import org.hibernate.engine.spi.PersistenceContext;
41
import org.hibernate.engine.spi.SessionFactoryImplementor;
42
import org.hibernate.engine.spi.SessionImplementor;
43
import org.hibernate.internal.util.ReflectHelper;
44
import org.hibernate.persister.entity.EntityPersister;
45
import org.hibernate.persister.entity.Joinable;
46
import org.hibernate.persister.entity.UniqueKeyLoadable;
47
import org.hibernate.proxy.HibernateProxy;
48
import org.hibernate.tuple.ElementWrapper;
49

  
50
/**
51
 * Base for types which map associations to persistent entities.
52
 *
53
 * Note : This class overrides the Hibernate EntityType class to provide a
54
 * workaround for problem in method 'replace'. Need to check if
55
 * this problem is fixed in later versions of hibernate or open a bug report
56
 * with a patch. This overriding class appears both in the 'cdmlib-persistence'
57
 * and the 'cdmlib-remote-webapp' projects to ensure that it is loaded with
58
 * priority before the original class.
59
 *
60
 * @author Gavin King
61
 */
62
public abstract class EntityType extends AbstractType implements AssociationType {
63

  
64
	private final TypeFactory.TypeScope scope;
65
	private final String associatedEntityName;
66
	protected final String uniqueKeyPropertyName;
67
	protected final boolean isEmbeddedInXML;
68
	private final boolean eager;
69
	private final boolean unwrapProxy;
70

  
71
	private transient Class returnedClass;
72

  
73
	/**
74
	 * Constructs the requested entity type mapping.
75
	 *
76
	 * @param scope The type scope
77
	 * @param entityName The name of the associated entity.
78
	 * @param uniqueKeyPropertyName The property-ref name, or null if we
79
	 * reference the PK of the associated entity.
80
	 * @param eager Is eager fetching enabled.
81
	 * @param isEmbeddedInXML Should values of this mapping be embedded in XML modes?
82
	 * @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping
83
	 * says to return the "implementation target" of lazy prooxies; typically only possible
84
	 * with lazy="no-proxy".
85
	 *
86
	 * @deprecated Use {@link #EntityType(TypeFactory.TypeScope, String, String, boolean, boolean )} instead.
87
	 * See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
88
	 */
89
	@Deprecated
90
	protected EntityType(
91
			TypeFactory.TypeScope scope,
92
			String entityName,
93
			String uniqueKeyPropertyName,
94
			boolean eager,
95
			boolean isEmbeddedInXML,
96
			boolean unwrapProxy) {
97
		this.scope = scope;
98
		this.associatedEntityName = entityName;
99
		this.uniqueKeyPropertyName = uniqueKeyPropertyName;
100
		this.isEmbeddedInXML = isEmbeddedInXML;
101
		this.eager = eager;
102
		this.unwrapProxy = unwrapProxy;
103
	}
104

  
105
	/**
106
	 * Constructs the requested entity type mapping.
107
	 *
108
	 * @param scope The type scope
109
	 * @param entityName The name of the associated entity.
110
	 * @param uniqueKeyPropertyName The property-ref name, or null if we
111
	 * reference the PK of the associated entity.
112
	 * @param eager Is eager fetching enabled.
113
	 * @param unwrapProxy Is unwrapping of proxies allowed for this association; unwrapping
114
	 * says to return the "implementation target" of lazy prooxies; typically only possible
115
	 * with lazy="no-proxy".
116
	 */
117
	protected EntityType(
118
			TypeFactory.TypeScope scope,
119
			String entityName,
120
			String uniqueKeyPropertyName,
121
			boolean eager,
122
			boolean unwrapProxy) {
123
		this.scope = scope;
124
		this.associatedEntityName = entityName;
125
		this.uniqueKeyPropertyName = uniqueKeyPropertyName;
126
		this.isEmbeddedInXML = true;
127
		this.eager = eager;
128
		this.unwrapProxy = unwrapProxy;
129
	}
130

  
131
	protected TypeFactory.TypeScope scope() {
132
		return scope;
133
	}
134

  
135
	/**
136
	 * An entity type is a type of association type
137
	 *
138
	 * @return True.
139
	 */
140
	@Override
141
    public boolean isAssociationType() {
142
		return true;
143
	}
144

  
145
	/**
146
	 * Explicitly, an entity type is an entity type ;)
147
	 *
148
	 * @return True.
149
	 */
150
	@Override
151
    public final boolean isEntityType() {
152
		return true;
153
	}
154

  
155
	/**
156
	 * {@inheritDoc}
157
	 */
158
	@Override
159
    public boolean isMutable() {
160
		return false;
161
	}
162

  
163
	/**
164
	 * Generates a string representation of this type.
165
	 *
166
	 * @return string rep
167
	 */
168
	@Override
169
    public String toString() {
170
		return getClass().getName() + '(' + getAssociatedEntityName() + ')';
171
	}
172

  
173
	/**
174
	 * For entity types, the name correlates to the associated entity name.
175
	 */
176
	@Override
177
    public String getName() {
178
		return associatedEntityName;
179
	}
180

  
181
	/**
182
	 * Does this association foreign key reference the primary key of the other table?
183
	 * Otherwise, it references a property-ref.
184
	 *
185
	 * @return True if this association reference the PK of the associated entity.
186
	 */
187
	public boolean isReferenceToPrimaryKey() {
188
		return uniqueKeyPropertyName==null;
189
	}
190

  
191
	@Override
192
    public String getRHSUniqueKeyPropertyName() {
193
		return uniqueKeyPropertyName;
194
	}
195

  
196
	@Override
197
    public String getLHSPropertyName() {
198
		return null;
199
	}
200

  
201
	public String getPropertyName() {
202
		return null;
203
	}
204

  
205
	/**
206
	 * The name of the associated entity.
207
	 *
208
	 * @return The associated entity name.
209
	 */
210
	public final String getAssociatedEntityName() {
211
		return associatedEntityName;
212
	}
213

  
214
	/**
215
	 * The name of the associated entity.
216
	 *
217
	 * @param factory The session factory, for resolution.
218
	 * @return The associated entity name.
219
	 */
220
	@Override
221
    public String getAssociatedEntityName(SessionFactoryImplementor factory) {
222
		return getAssociatedEntityName();
223
	}
224

  
225
	/**
226
	 * Retrieves the {@link Joinable} defining the associated entity.
227
	 *
228
	 * @param factory The session factory.
229
	 * @return The associated joinable
230
	 * @throws MappingException Generally indicates an invalid entity name.
231
	 */
232
	@Override
233
    public Joinable getAssociatedJoinable(SessionFactoryImplementor factory) throws MappingException {
234
		return ( Joinable ) factory.getEntityPersister( associatedEntityName );
235
	}
236

  
237
	/**
238
	 * This returns the wrong class for an entity with a proxy, or for a named
239
	 * entity.  Theoretically it should return the proxy class, but it doesn't.
240
	 * <p/>
241
	 * The problem here is that we do not necessarily have a ref to the associated
242
	 * entity persister (nor to the session factory, to look it up) which is really
243
	 * needed to "do the right thing" here...
244
	 *
245
	 * @return The entiyt class.
246
	 */
247
	@Override
248
    public final Class getReturnedClass() {
249
		if ( returnedClass == null ) {
250
			returnedClass = determineAssociatedEntityClass();
251
		}
252
		return returnedClass;
253
	}
254

  
255
	private Class determineAssociatedEntityClass() {
256
		try {
257
			return ReflectHelper.classForName( getAssociatedEntityName() );
258
		}
259
		catch ( ClassNotFoundException cnfe ) {
260
			return java.util.Map.class;
261
		}
262
	}
263

  
264
	/**
265
	 * {@inheritDoc}
266
	 */
267
	@Override
268
    public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
269
	throws HibernateException, SQLException {
270
		return nullSafeGet( rs, new String[] {name}, session, owner );
271
	}
272

  
273
	/**
274
	 * {@inheritDoc}
275
	 */
276
	@Override
277
    public final Object nullSafeGet(
278
			ResultSet rs,
279
			String[] names,
280
			SessionImplementor session,
281
			Object owner) throws HibernateException, SQLException {
282
		return resolve( hydrate(rs, names, session, owner), session, owner );
283
	}
284

  
285
	/**
286
	 * Two entities are considered the same when their instances are the same.
287
	 *
288
	 *
289
	 * @param x One entity instance
290
	 * @param y Another entity instance
291
	 * @return True if x == y; false otherwise.
292
	 */
293
	@Override
294
    public final boolean isSame(Object x, Object y) {
295
		return x == y;
296
	}
297

  
298
	/**
299
	 * {@inheritDoc}
300
	 */
301
	@Override
302
    public int compare(Object x, Object y) {
303
		return 0; //TODO: entities CAN be compared, by PK, fix this! -> only if/when we can extract the id values....
304
	}
305

  
306
	/**
307
	 * {@inheritDoc}
308
	 */
309
	@Override
310
    public Object deepCopy(Object value, SessionFactoryImplementor factory) {
311
		return value; //special case ... this is the leaf of the containment graph, even though not immutable
312
	}
313

  
314
	/**
315
	 * {@inheritDoc}
316
	 */
317
	@Override
318
    public Object replace(
319
			Object original,
320
			Object target,
321
			SessionImplementor session,
322
			Object owner,
323
			Map copyCache) throws HibernateException {
324
		if ( original == null ) {
325
			return null;
326
		}
327
		Object cached = copyCache.get(original);
328
		if ( cached != null ) {
329
			return cached;
330
		}
331
		else {
332
			if ( original == target ) {
333
				return target;
334
			}
335
			if ( session.getContextEntityIdentifier( original ) == null  &&
336
					ForeignKeys.isTransient( associatedEntityName, original, Boolean.FALSE, session ) ) {
337
			    // final Object copy = session.getFactory().getEntityPersister( associatedEntityName )
338
                //  .instantiate( null, session );
339
			    // changed above call to below, because the associatedEntityName could be an abstract class
340
			    // in which case it cannot be instantiated
341

  
342
				final Object copy = session.getFactory().getEntityPersister( original.getClass().getName() )
343
						.instantiate( null, session );
344
				//TODO: should this be Session.instantiate(Persister, ...)?
345
				copyCache.put( original, copy );
346
				return copy;
347
			}
348
			else {
349
				Object id = getIdentifier( original, session );
350
				if ( id == null ) {
351
					throw new AssertionFailure("non-transient entity has a null id");
352
				}
353
				id = getIdentifierOrUniqueKeyType( session.getFactory() )
354
						.replace(id, null, session, owner, copyCache);
355
				return resolve( id, session, owner );
356
			}
357
		}
358
	}
359

  
360
	/**
361
	 * {@inheritDoc}
362
	 */
363
	@Override
364
    public int getHashCode(Object x, SessionFactoryImplementor factory) {
365
		EntityPersister persister = factory.getEntityPersister(associatedEntityName);
366
		if ( !persister.canExtractIdOutOfEntity() ) {
367
			return super.getHashCode( x );
368
		}
369

  
370
		final Serializable id;
371
		if (x instanceof HibernateProxy) {
372
			id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getIdentifier();
373
		}
374
		else {
375
			final Class mappedClass = persister.getMappedClass();
376
			if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
377
				id = persister.getIdentifier( x );
378
			}
379
			else {
380
				id = (Serializable) x;
381
			}
382
		}
383
		return persister.getIdentifierType().getHashCode( id, factory );
384
	}
385

  
386
	@Override
387
	public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) {
388
		// associations (many-to-one and one-to-one) can be null...
389
		if ( x == null || y == null ) {
390
			return x == y;
391
		}
392

  
393
		EntityPersister persister = factory.getEntityPersister(associatedEntityName);
394
		if ( !persister.canExtractIdOutOfEntity() ) {
395
			return super.isEqual(x, y );
396
		}
397

  
398
		final Class mappedClass = persister.getMappedClass();
399
		Serializable xid;
400
		if (x instanceof HibernateProxy) {
401
			xid = ( (HibernateProxy) x ).getHibernateLazyInitializer()
402
					.getIdentifier();
403
		}
404
		else {
405
			if ( mappedClass.isAssignableFrom( x.getClass() ) ) {
406
				xid = persister.getIdentifier( x );
407
			}
408
			else {
409
				//JPA 2 case where @IdClass contains the id and not the associated entity
410
				xid = (Serializable) x;
411
			}
412
		}
413

  
414
		Serializable yid;
415
		if (y instanceof HibernateProxy) {
416
			yid = ( (HibernateProxy) y ).getHibernateLazyInitializer()
417
					.getIdentifier();
418
		}
419
		else {
420
			if ( mappedClass.isAssignableFrom( y.getClass() ) ) {
421
				yid = persister.getIdentifier( y );
422
			}
423
			else {
424
				//JPA 2 case where @IdClass contains the id and not the associated entity
425
				yid = (Serializable) y;
426
			}
427
		}
428

  
429
		return persister.getIdentifierType()
430
				.isEqual(xid, yid, factory);
431
	}
432

  
433
	/**
434
	 * {@inheritDoc}
435
	 */
436
	@Override
437
    public boolean isEmbeddedInXML() {
438
		return isEmbeddedInXML;
439
	}
440

  
441
	/**
442
	 * {@inheritDoc}
443
	 */
444
	@Override
445
    public boolean isXMLElement() {
446
		return isEmbeddedInXML;
447
	}
448

  
449
	/**
450
	 * {@inheritDoc}
451
	 */
452
	@Override
453
    public Object fromXMLNode(Node xml, Mapping factory) throws HibernateException {
454
		if ( !isEmbeddedInXML ) {
455
			return getIdentifierType(factory).fromXMLNode(xml, factory);
456
		}
457
		else {
458
			return xml;
459
		}
460
	}
461

  
462
	/**
463
	 * {@inheritDoc}
464
	 */
465
	@Override
466
    public void setToXMLNode(Node node, Object value, SessionFactoryImplementor factory) throws HibernateException {
467
		if ( !isEmbeddedInXML ) {
468
			getIdentifierType(factory).setToXMLNode(node, value, factory);
469
		}
470
		else {
471
			Element elt = (Element) value;
472
			replaceNode( node, new ElementWrapper(elt) );
473
		}
474
	}
475

  
476
	@Override
477
    public String getOnCondition(String alias, SessionFactoryImplementor factory, Map enabledFilters)
478
	throws MappingException {
479
		if ( isReferenceToPrimaryKey() ) { //TODO: this is a bit arbitrary, expose a switch to the user?
480
			return "";
481
		}
482
		else {
483
			return getAssociatedJoinable( factory ).filterFragment( alias, enabledFilters );
484
		}
485
	}
486

  
487
	/**
488
	 * Resolve an identifier or unique key value
489
	 */
490
	@Override
491
    public Object resolve(Object value, SessionImplementor session, Object owner) throws HibernateException {
492
		if ( isNotEmbedded( session ) ) {
493
			return value;
494
		}
495

  
496
		if ( value == null ) {
497
			return null;
498
		}
499
		else {
500
			if ( isNull( owner, session ) ) {
501
				return null; //EARLY EXIT!
502
			}
503

  
504
			if ( isReferenceToPrimaryKey() ) {
505
				return resolveIdentifier( (Serializable) value, session );
506
			}
507
			else {
508
				return loadByUniqueKey( getAssociatedEntityName(), uniqueKeyPropertyName, value, session );
509
			}
510
		}
511
	}
512

  
513
	@Override
514
    public Type getSemiResolvedType(SessionFactoryImplementor factory) {
515
		return factory.getEntityPersister( associatedEntityName ).getIdentifierType();
516
	}
517

  
518
	protected final Object getIdentifier(Object value, SessionImplementor session) throws HibernateException {
519
		if ( isNotEmbedded(session) ) {
520
			return value;
521
		}
522

  
523
		if ( isReferenceToPrimaryKey() ) {
524
			return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, session ); //tolerates nulls
525
		}
526
		else if ( value == null ) {
527
			return null;
528
		}
529
		else {
530
			EntityPersister entityPersister = session.getFactory().getEntityPersister( getAssociatedEntityName() );
531
			Object propertyValue = entityPersister.getPropertyValue( value, uniqueKeyPropertyName );
532
			// We now have the value of the property-ref we reference.  However,
533
			// we need to dig a little deeper, as that property might also be
534
			// an entity type, in which case we need to resolve its identitifier
535
			Type type = entityPersister.getPropertyType( uniqueKeyPropertyName );
536
			if ( type.isEntityType() ) {
537
				propertyValue = ( ( EntityType ) type ).getIdentifier( propertyValue, session );
538
			}
539

  
540
			return propertyValue;
541
		}
542
	}
543

  
544
	/**
545
	 * @deprecated To be removed in 5.  Removed as part of removing the notion of DOM entity-mode.
546
	 * See Jira issue: <a href="https://hibernate.onjira.com/browse/HHH-7771">HHH-7771</a>
547
	 */
548
	@Deprecated
549
	protected boolean isNotEmbedded(SessionImplementor session) {
550
//		return !isEmbeddedInXML;
551
		return false;
552
	}
553

  
554
	/**
555
	 * Generate a loggable representation of an instance of the value mapped by this type.
556
	 *
557
	 * @param value The instance to be logged.
558
	 * @param factory The session factory.
559
	 * @return The loggable string.
560
	 * @throws HibernateException Generally some form of resolution problem.
561
	 */
562
	@Override
563
    public String toLoggableString(Object value, SessionFactoryImplementor factory) {
564
		if ( value == null ) {
565
			return "null";
566
		}
567

  
568
		EntityPersister persister = factory.getEntityPersister( associatedEntityName );
569
		StringBuilder result = new StringBuilder().append( associatedEntityName );
570

  
571
		if ( persister.hasIdentifierProperty() ) {
572
			final EntityMode entityMode = persister.getEntityMode();
573
			final Serializable id;
574
			if ( entityMode == null ) {
575
				if ( isEmbeddedInXML ) {
576
					throw new ClassCastException( value.getClass().getName() );
577
				}
578
				id = ( Serializable ) value;
579
			} else if ( value instanceof HibernateProxy ) {
580
				HibernateProxy proxy = ( HibernateProxy ) value;
581
				id = proxy.getHibernateLazyInitializer().getIdentifier();
582
			}
583
			else {
584
				id = persister.getIdentifier( value );
585
			}
586

  
587
			result.append( '#' )
588
				.append( persister.getIdentifierType().toLoggableString( id, factory ) );
589
		}
590

  
591
		return result.toString();
592
	}
593

  
594
	/**
595
	 * Is the association modeled here defined as a 1-1 in the database (physical model)?
596
	 *
597
	 * @return True if a 1-1 in the database; false otherwise.
598
	 */
599
	public abstract boolean isOneToOne();
600

  
601
	/**
602
	 * Is the association modeled here a 1-1 according to the logical moidel?
603
	 *
604
	 * @return True if a 1-1 in the logical model; false otherwise.
605
	 */
606
	public boolean isLogicalOneToOne() {
607
		return isOneToOne();
608
	}
609

  
610
	/**
611
	 * Convenience method to locate the identifier type of the associated entity.
612
	 *
613
	 * @param factory The mappings...
614
	 * @return The identifier type
615
	 */
616
	Type getIdentifierType(Mapping factory) {
617
		return factory.getIdentifierType( getAssociatedEntityName() );
618
	}
619

  
620
	/**
621
	 * Convenience method to locate the identifier type of the associated entity.
622
	 *
623
	 * @param session The originating session
624
	 * @return The identifier type
625
	 */
626
	Type getIdentifierType(SessionImplementor session) {
627
		return getIdentifierType( session.getFactory() );
628
	}
629

  
630
	/**
631
	 * Determine the type of either (1) the identifier if we reference the
632
	 * associated entity's PK or (2) the unique key to which we refer (i.e.
633
	 * the property-ref).
634
	 *
635
	 * @param factory The mappings...
636
	 * @return The appropriate type.
637
	 * @throws MappingException Generally, if unable to resolve the associated entity name
638
	 * or unique key property name.
639
	 */
640
	public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException {
641
		if ( isReferenceToPrimaryKey() ) {
642
			return getIdentifierType(factory);
643
		}
644
		else {
645
			Type type = factory.getReferencedPropertyType( getAssociatedEntityName(), uniqueKeyPropertyName );
646
			if ( type.isEntityType() ) {
647
				type = ( ( EntityType ) type).getIdentifierOrUniqueKeyType( factory );
648
			}
649
			return type;
650
		}
651
	}
652

  
653
	/**
654
	 * The name of the property on the associated entity to which our FK
655
	 * refers
656
	 *
657
	 * @param factory The mappings...
658
	 * @return The appropriate property name.
659
	 * @throws MappingException Generally, if unable to resolve the associated entity name
660
	 */
661
	public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory)
662
	throws MappingException {
663
		if ( isReferenceToPrimaryKey() ) {
664
			return factory.getIdentifierPropertyName( getAssociatedEntityName() );
665
		}
666
		else {
667
			return uniqueKeyPropertyName;
668
		}
669
	}
670

  
671
	protected abstract boolean isNullable();
672

  
673
	/**
674
	 * Resolve an identifier via a load.
675
	 *
676
	 * @param id The entity id to resolve
677
	 * @param session The orginating session.
678
	 * @return The resolved identifier (i.e., loaded entity).
679
	 * @throws org.hibernate.HibernateException Indicates problems performing the load.
680
	 */
681
	protected final Object resolveIdentifier(Serializable id, SessionImplementor session) throws HibernateException {
682
		boolean isProxyUnwrapEnabled = unwrapProxy &&
683
				session.getFactory()
684
						.getEntityPersister( getAssociatedEntityName() )
685
						.isInstrumented();
686

  
687
		Object proxyOrEntity = session.internalLoad(
688
				getAssociatedEntityName(),
689
				id,
690
				eager,
691
				isNullable() && !isProxyUnwrapEnabled
692
		);
693

  
694
		if ( proxyOrEntity instanceof HibernateProxy ) {
695
			( ( HibernateProxy ) proxyOrEntity ).getHibernateLazyInitializer()
696
					.setUnwrap( isProxyUnwrapEnabled );
697
		}
698

  
699
		return proxyOrEntity;
700
	}
701

  
702
	protected boolean isNull(Object owner, SessionImplementor session) {
703
		return false;
704
	}
705

  
706
	/**
707
	 * Load an instance by a unique key that is not the primary key.
708
	 *
709
	 * @param entityName The name of the entity to load
710
	 * @param uniqueKeyPropertyName The name of the property defining the uniqie key.
711
	 * @param key The unique key property value.
712
	 * @param session The originating session.
713
	 * @return The loaded entity
714
	 * @throws HibernateException generally indicates problems performing the load.
715
	 */
716
	public Object loadByUniqueKey(
717
			String entityName,
718
			String uniqueKeyPropertyName,
719
			Object key,
720
			SessionImplementor session) throws HibernateException {
721
		final SessionFactoryImplementor factory = session.getFactory();
722
		UniqueKeyLoadable persister = ( UniqueKeyLoadable ) factory.getEntityPersister( entityName );
723

  
724
		//TODO: implement caching?! proxies?!
725

  
726
		EntityUniqueKey euk = new EntityUniqueKey(
727
				entityName,
728
				uniqueKeyPropertyName,
729
				key,
730
				getIdentifierOrUniqueKeyType( factory ),
731
				persister.getEntityMode(),
732
				session.getFactory()
733
		);
734

  
735
		final PersistenceContext persistenceContext = session.getPersistenceContext();
736
		Object result = persistenceContext.getEntity( euk );
737
		if ( result == null ) {
738
			result = persister.loadByUniqueKey( uniqueKeyPropertyName, key, session );
739
		}
740
		return result == null ? null : persistenceContext.proxyFor( result );
741
	}
742

  
743
}

Also available in: Unified diff