Skip to content

Commit fa79851

Browse files
committed
HHH-15739 deprecate @LazyToOne and @LazyCollection + introduce @Proxyless
- @Proxyless replaces @LazyToOne - static methods of Hibernate replace @LazyCollection
1 parent caff907 commit fa79851

File tree

7 files changed

+120
-2
lines changed

7 files changed

+120
-2
lines changed

hibernate-core/src/main/java/org/hibernate/Hibernate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
* the Hibernate metamodel, to write such generic code for any given serialization
6060
* library, but the details depend on what facilities the library itself offers for
6161
* the program to intervene in the process of serialization and of deserialization.
62+
* <p>
63+
* See {@linkplain org.hibernate.annotations.Proxyless this discussion of proxies in
64+
* Hibernate}.
6265
*
6366
* @author Gavin King
6467
*/

hibernate-core/src/main/java/org/hibernate/annotations/LazyCollection.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import java.lang.annotation.Retention;
1111
import java.lang.annotation.RetentionPolicy;
1212
import java.lang.annotation.Target;
13+
import java.util.Collection;
14+
import java.util.Map;
1315

1416
/**
1517
* Specify the laziness of a collection, either a
@@ -22,7 +24,19 @@
2224
* extra-lazy collection fetching}.
2325
*
2426
* @author Emmanuel Bernard
27+
*
28+
* @deprecated
29+
* <ul>
30+
* <li>Use the JPA-defined {@link jakarta.persistence.FetchType#EAGER}
31+
* instead of {@code LazyCollection(FALSE)}.
32+
* <li>Use static methods of {@link org.hibernate.Hibernate},
33+
* for example {@link org.hibernate.Hibernate#size(Collection)},
34+
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
35+
* or {@link org.hibernate.Hibernate#get(Map, Object)} instead
36+
* of {@code LazyCollection(EXTRA)}.
37+
* </ul>
2538
*/
39+
@Deprecated
2640
@Target({ElementType.METHOD, ElementType.FIELD})
2741
@Retention(RetentionPolicy.RUNTIME)
2842
public @interface LazyCollection {

hibernate-core/src/main/java/org/hibernate/annotations/LazyCollectionOption.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
*/
77
package org.hibernate.annotations;
88

9+
import java.util.Collection;
10+
import java.util.Map;
11+
912
/**
1013
* Enumerates the options for lazy loading of a
1114
* {@linkplain jakarta.persistence.ElementCollection collection},
@@ -15,7 +18,19 @@
1518
* @author Emmanuel Bernard
1619
*
1720
* @see LazyCollection
21+
*
22+
* @deprecated
23+
* <ul>
24+
* <li>Use the JPA-defined {@link jakarta.persistence.FetchType#EAGER}
25+
* instead of {@code LazyCollection(FALSE)}.
26+
* <li>Use static methods of {@link org.hibernate.Hibernate},
27+
* for example {@link org.hibernate.Hibernate#size(Collection)},
28+
* {@link org.hibernate.Hibernate#contains(Collection, Object)},
29+
* or {@link org.hibernate.Hibernate#get(Map, Object)} instead
30+
* of {@code LazyCollection(EXTRA)}.
31+
* </ul>
1832
*/
33+
@Deprecated
1934
public enum LazyCollectionOption {
2035
/**
2136
* The collection is always loaded eagerly, and all its

hibernate-core/src/main/java/org/hibernate/annotations/LazyToOne.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@
5959
* and instead falls back to using a proxy!</strong>
6060
*
6161
* @author Emmanuel Bernard
62+
*
63+
* @deprecated use {@link Proxyless @Proxyless}
6264
*/
65+
@Deprecated
6366
@Target({ElementType.METHOD, ElementType.FIELD})
6467
@Retention(RetentionPolicy.RUNTIME)
6568
public @interface LazyToOne {

hibernate-core/src/main/java/org/hibernate/annotations/LazyToOneOption.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
* @author Emmanuel Bernard
1616
*
1717
* @see LazyToOne
18+
*
19+
* @deprecated use {@link Proxyless @Proxyless}
1820
*/
21+
@Deprecated
1922
public enum LazyToOneOption {
2023
/**
2124
* The association is always loaded eagerly. The identifier
@@ -38,7 +41,8 @@ public enum LazyToOneOption {
3841
* <li>The proxy does not have the same concrete type as the
3942
* proxied delegate, and so
4043
* {@link org.hibernate.Hibernate#getClass(Object)}
41-
* must be used in place of {@link Object#getClass()}.
44+
* must be used in place of {@link Object#getClass()},
45+
* and this method fetches the entity by side-effect.
4246
* <li>For a polymorphic association, the concrete type of
4347
* the proxied entity instance is not known until the
4448
* delegate is fetched from the database, and so
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.annotations;
8+
9+
import java.lang.annotation.ElementType;
10+
import java.lang.annotation.Retention;
11+
import java.lang.annotation.RetentionPolicy;
12+
import java.lang.annotation.Target;
13+
14+
/**
15+
* Specifies that the program should not be exposed to a
16+
* synthetic proxy object when the annotated lazily-fetched
17+
* {@linkplain jakarta.persistence.OneToOne one to one} or
18+
* {@linkplain jakarta.persistence.ManyToOne many to one}
19+
* association is unfetched. This annotation has no effect
20+
* on eager associations.
21+
* <p>
22+
* By default, that is, when an association is <em>not</em>
23+
* annotated {@code Proxyless}, an unfetched lazy association
24+
* is represented by a <em>proxy object</em> which holds the
25+
* identifier (foreign key) of the associated entity instance.
26+
* <ul>
27+
* <li>The identifier property of the proxy object is set
28+
* when the proxy is instantiated.
29+
* The program may obtain the entity identifier value
30+
* of an unfetched proxy, without triggering lazy
31+
* fetching, by calling the corresponding getter method.
32+
* (It's even possible to set an association to reference
33+
* an unfetched proxy.)
34+
* <li>A delegate entity instance is lazily fetched when any
35+
* other method of the proxy is called.
36+
* <li>The proxy does not have the same concrete type as the
37+
* proxied delegate, and so
38+
* {@link org.hibernate.Hibernate#getClass(Object)}
39+
* must be used in place of {@link Object#getClass()},
40+
* and this method fetches the entity by side-effect.
41+
* <li>For a polymorphic association, the concrete type of
42+
* the proxied entity instance is not known until the
43+
* delegate is fetched from the database, and so
44+
* {@link org.hibernate.Hibernate#unproxy(Object, Class)}}
45+
* must be used to perform typecasts, and
46+
* {@link org.hibernate.Hibernate#getClass(Object)}
47+
* must be used instead of the Java {@code instanceof}
48+
* operator.
49+
* </ul>
50+
* When an association is annotated {@code Proxyless}, there
51+
* is no such indirection, but the associated entity instance
52+
* is initially in an unloaded state, with only its identifier
53+
* field set.
54+
* <ul>
55+
* <li>The identifier field of an unloaded entity instance is
56+
* set when the unloaded instance is instantiated.
57+
* The program may obtain the identifier of an unloaded
58+
* entity, without triggering lazy loading, by accessing
59+
* the field containing the identifier.
60+
* <li>The remaining non-lazy state of the entity instance is
61+
* loaded lazily when any other field is accessed.
62+
* <li>Typecasts, the Java {@code instanceof} operator, and
63+
* {@link Object#getClass()} may be used as normal.
64+
* <li>Bytecode enhancement is required.
65+
* </ul>
66+
* <strong>Currently, Hibernate does not support {@code
67+
* Proxyless} for polymorphic associations </strong>
68+
*
69+
*/
70+
@Target({ElementType.METHOD, ElementType.FIELD})
71+
@Retention(RetentionPolicy.RUNTIME)
72+
public @interface Proxyless {
73+
}

hibernate-core/src/main/java/org/hibernate/cfg/ToOneBinder.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.hibernate.annotations.NotFoundAction;
3333
import org.hibernate.annotations.OnDelete;
3434
import org.hibernate.annotations.OnDeleteAction;
35+
import org.hibernate.annotations.Proxyless;
3536
import org.hibernate.annotations.common.reflection.XClass;
3637
import org.hibernate.annotations.common.reflection.XProperty;
3738
import org.hibernate.boot.spi.MetadataBuildingContext;
@@ -304,11 +305,16 @@ static void defineFetchingStrategy(
304305

305306
final LazyToOne lazy = property.getAnnotation( LazyToOne.class );
306307
final NotFound notFound = property.getAnnotation( NotFound.class );
308+
final boolean proxyless = property.isAnnotationPresent( Proxyless.class );
307309
if ( notFound != null ) {
308310
toOne.setLazy( false );
309311
toOne.setUnwrapProxy( true );
310312
}
311313
else if ( lazy != null ) {
314+
if ( proxyless ) {
315+
throw new AnnotationException("Association '" + getPath( propertyHolder, inferredData )
316+
+ "' is annotated '@Proxyless' and '@LazyToOne'");
317+
}
312318
boolean lazyFalse = lazy.value() == LazyToOneOption.FALSE;
313319
if ( fetchType == FetchType.LAZY && lazyFalse ) {
314320
throw new AnnotationException("Association '" + getPath( propertyHolder, inferredData )
@@ -319,7 +325,7 @@ else if ( lazy != null ) {
319325
}
320326
else {
321327
toOne.setLazy( fetchType == FetchType.LAZY );
322-
toOne.setUnwrapProxy( fetchType != FetchType.LAZY );
328+
toOne.setUnwrapProxy( proxyless || fetchType == FetchType.EAGER );
323329
toOne.setUnwrapProxyImplicit( true );
324330
}
325331

0 commit comments

Comments
 (0)