HHH-18194 - Remove @Proxy
This commit is contained in:
parent
53bca2467d
commit
4309cffb4d
|
@ -453,50 +453,6 @@ when executing an HQL or JPQL which selects from the `AccountSummary` entity,
|
|||
Hibernate will trigger a Persistence Context flush if there are pending `Account`, `Client` or `AccountTransaction` entity state transitions.
|
||||
====
|
||||
|
||||
[[entity-proxy]]
|
||||
==== Define a custom entity proxy
|
||||
|
||||
By default, when it needs to use a proxy instead of the actual POJO, Hibernate is going to use a Bytecode manipulation library like
|
||||
https://bytebuddy.net/[Byte Buddy].
|
||||
|
||||
However, if the entity class is final, a proxy will not be created; you will get a POJO even when you only need a proxy reference.
|
||||
In this case, you could proxy an interface that this particular entity implements, as illustrated by the following example.
|
||||
|
||||
NOTE: Supplying a custom proxy class has been allowed historically, but has never seen much use. Also, setting the `lazy` property to `false`, effectively disallowing proxy creation for an entity type, can easily lead to performance degradation due to the N + 1 query issue. As of 6.2 `@Proxy` has been formally deprecated.
|
||||
|
||||
See the <<concrete-proxy,@ConcreteProxy>> paragraph if you wish to resolve the concrete type of proxies for the purpose of `instanceof` checks and typecasts.
|
||||
|
||||
[[entity-proxy-interface-mapping]]
|
||||
.Final entity class implementing the `Identifiable` interface
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{example-dir-proxy}/ProxyInterfaceTest.java[tag=entity-proxy-interface-mapping,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Proxy.html[`@Proxy`]
|
||||
annotation is used to specify a custom proxy implementation for the current annotated entity.
|
||||
|
||||
When loading the `Book` entity proxy, Hibernate is going to proxy the `Identifiable` interface instead as illustrated by the following example:
|
||||
|
||||
[[entity-proxy-persist-mapping]]
|
||||
.Proxying the final entity class implementing the `Identifiable` interface
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{example-dir-proxy}/ProxyInterfaceTest.java[tag=entity-proxy-persist-mapping,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{extrasdir}/entity/entity-proxy-persist-mapping.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
As you can see in the associated SQL snippet, Hibernate issues no SQL SELECT query since the proxy can be
|
||||
constructed without needing to fetch the actual entity POJO.
|
||||
|
||||
[[concrete-proxy]]
|
||||
==== Create proxies that resolve their inheritance subtype
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* 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.annotations;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Allows the proxy class of an entity class to be explicitly specified.
|
||||
*
|
||||
* @deprecated This annotation is almost never useful.
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Deprecated(since = "6.2")
|
||||
@Target(TYPE)
|
||||
@Retention(RUNTIME)
|
||||
public @interface Proxy {
|
||||
/**
|
||||
* Whether this class may be proxied. Default to true.
|
||||
*/
|
||||
boolean lazy() default true;
|
||||
|
||||
/**
|
||||
* Proxy class or interface used. Default is to the annotated entity class itself.
|
||||
*/
|
||||
Class<?> proxyClass() default void.class;
|
||||
}
|
|
@ -37,7 +37,6 @@ import org.hibernate.annotations.NaturalIdCache;
|
|||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OptimisticLockType;
|
||||
import org.hibernate.annotations.OptimisticLocking;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.annotations.QueryCacheLayout;
|
||||
import org.hibernate.annotations.RowId;
|
||||
import org.hibernate.annotations.SQLDelete;
|
||||
|
@ -1590,27 +1589,9 @@ public class EntityBinder {
|
|||
}
|
||||
|
||||
public void bindProxy() {
|
||||
final Proxy proxy = annotatedClass.getAnnotationUsage( Proxy.class, getSourceModelContext() );
|
||||
if ( proxy != null ) {
|
||||
lazy = proxy.lazy();
|
||||
proxyClass = lazy ? resolveProxyClass( proxy, annotatedClass, getSourceModelContext() ) : null;
|
||||
}
|
||||
else {
|
||||
//needed to allow association lazy loading.
|
||||
lazy = true;
|
||||
proxyClass = annotatedClass;
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassDetails resolveProxyClass(
|
||||
Proxy proxy,
|
||||
ClassDetails annotatedClass,
|
||||
SourceModelBuildingContext sourceModelContext) {
|
||||
final Class<?> explicitProxyClass = proxy.proxyClass();
|
||||
if ( explicitProxyClass == void.class ) {
|
||||
return annotatedClass;
|
||||
}
|
||||
return sourceModelContext.getClassDetailsRegistry().resolveClassDetails( explicitProxyClass.getName() );
|
||||
//needed to allow association lazy loading.
|
||||
lazy = true;
|
||||
proxyClass = annotatedClass;
|
||||
}
|
||||
|
||||
public void bindConcreteProxy() {
|
||||
|
|
|
@ -488,10 +488,6 @@ public interface HibernateAnnotations {
|
|||
PartitionKey.class,
|
||||
PartitionKeyAnnotation.class
|
||||
);
|
||||
OrmAnnotationDescriptor<Proxy,ProxyAnnotation> PROXY = new OrmAnnotationDescriptor<>(
|
||||
Proxy.class,
|
||||
ProxyAnnotation.class
|
||||
);
|
||||
OrmAnnotationDescriptor<PropertyRef,PropertyRefAnnotation> PROPERTY_REF = new OrmAnnotationDescriptor<>(
|
||||
PropertyRef.class,
|
||||
PropertyRefAnnotation.class
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* 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.boot.models.annotations.internal;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.boot.models.HibernateAnnotations;
|
||||
import org.hibernate.models.spi.SourceModelBuildingContext;
|
||||
|
||||
import org.jboss.jandex.AnnotationInstance;
|
||||
|
||||
import static org.hibernate.boot.models.internal.OrmAnnotationHelper.extractJandexValue;
|
||||
|
||||
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
|
||||
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
|
||||
public class ProxyAnnotation implements Proxy {
|
||||
private boolean lazy;
|
||||
private java.lang.Class<?> proxyClass;
|
||||
|
||||
/**
|
||||
* Used in creating dynamic annotation instances (e.g. from XML)
|
||||
*/
|
||||
public ProxyAnnotation(SourceModelBuildingContext modelContext) {
|
||||
this.lazy = true;
|
||||
this.proxyClass = void.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in creating annotation instances from JDK variant
|
||||
*/
|
||||
public ProxyAnnotation(Proxy annotation, SourceModelBuildingContext modelContext) {
|
||||
this.lazy = annotation.lazy();
|
||||
this.proxyClass = annotation.proxyClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in creating annotation instances from Jandex variant
|
||||
*/
|
||||
public ProxyAnnotation(AnnotationInstance annotation, SourceModelBuildingContext modelContext) {
|
||||
this.lazy = extractJandexValue( annotation, HibernateAnnotations.PROXY, "lazy", modelContext );
|
||||
this.proxyClass = extractJandexValue( annotation, HibernateAnnotations.PROXY, "proxyClass", modelContext );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Proxy.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean lazy() {
|
||||
return lazy;
|
||||
}
|
||||
|
||||
public void lazy(boolean value) {
|
||||
this.lazy = value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public java.lang.Class<?> proxyClass() {
|
||||
return proxyClass;
|
||||
}
|
||||
|
||||
public void proxyClass(java.lang.Class<?> value) {
|
||||
this.proxyClass = value;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -16,7 +16,6 @@ import org.hibernate.annotations.BatchSize;
|
|||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.annotations.ResultCheckStyle;
|
||||
import org.hibernate.annotations.SQLDelete;
|
||||
import org.hibernate.annotations.SQLInsert;
|
||||
|
@ -40,7 +39,6 @@ import jakarta.persistence.Cacheable;
|
|||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
import static org.hibernate.boot.models.categorize.internal.CategorizationHelper.toClassDetails;
|
||||
import static org.hibernate.internal.util.StringHelper.EMPTY_STRINGS;
|
||||
import static org.hibernate.internal.util.StringHelper.isNotEmpty;
|
||||
import static org.hibernate.internal.util.StringHelper.unqualify;
|
||||
|
@ -106,29 +104,9 @@ public class EntityTypeMetadataImpl
|
|||
this.customUpdateMap = extractCustomSql( classDetails, SQLUpdate.class );
|
||||
this.customDeleteMap = extractCustomSql( classDetails, SQLDelete.class );
|
||||
|
||||
//noinspection deprecation
|
||||
final Proxy proxyAnnotation = classDetails.getDirectAnnotationUsage( Proxy.class );
|
||||
if ( proxyAnnotation != null ) {
|
||||
this.isLazy = proxyAnnotation.lazy();
|
||||
|
||||
if ( this.isLazy ) {
|
||||
final ClassDetails proxyClassDetails = toClassDetails( proxyAnnotation.proxyClass(), modelContext.getClassDetailsRegistry() );
|
||||
if ( proxyClassDetails != null ) {
|
||||
this.proxy = proxyClassDetails.getName();
|
||||
}
|
||||
else {
|
||||
this.proxy = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.proxy = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// defaults are that it is lazy and that the class itself is the proxy class
|
||||
this.isLazy = true;
|
||||
this.proxy = getEntityName();
|
||||
}
|
||||
// defaults are that it is lazy and that the class itself is the proxy class
|
||||
this.isLazy = true;
|
||||
this.proxy = getEntityName();
|
||||
|
||||
final DiscriminatorValue discriminatorValueAnn = classDetails.getDirectAnnotationUsage( DiscriminatorValue.class );
|
||||
if ( discriminatorValueAnn != null ) {
|
||||
|
@ -175,29 +153,9 @@ public class EntityTypeMetadataImpl
|
|||
this.customUpdateMap = extractCustomSql( classDetails, SQLUpdate.class );
|
||||
this.customDeleteMap = extractCustomSql( classDetails, SQLDelete.class );
|
||||
|
||||
//noinspection deprecation
|
||||
final Proxy proxyAnnotation = classDetails.getDirectAnnotationUsage( Proxy.class );
|
||||
if ( proxyAnnotation != null ) {
|
||||
this.isLazy = proxyAnnotation.lazy();
|
||||
|
||||
if ( this.isLazy ) {
|
||||
final ClassDetails proxyClassDetails = toClassDetails( proxyAnnotation.proxyClass(), modelContext.getClassDetailsRegistry() );
|
||||
if ( proxyClassDetails != null ) {
|
||||
this.proxy = proxyClassDetails.getName();
|
||||
}
|
||||
else {
|
||||
this.proxy = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.proxy = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// defaults are that it is lazy and that the class itself is the proxy class
|
||||
this.isLazy = true;
|
||||
this.proxy = getEntityName();
|
||||
}
|
||||
// defaults are that it is lazy and that the class itself is the proxy class
|
||||
this.isLazy = true;
|
||||
this.proxy = getEntityName();
|
||||
|
||||
final DiscriminatorValue discriminatorValueAnn = classDetails.getDirectAnnotationUsage( DiscriminatorValue.class );
|
||||
if ( discriminatorValueAnn != null ) {
|
||||
|
|
|
@ -228,27 +228,24 @@ public class BasicHibernateAnnotationsTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNonLazy() throws Exception {
|
||||
Session s;
|
||||
Transaction tx;
|
||||
s = openSession();
|
||||
tx = s.beginTransaction();
|
||||
Forest f = new Forest();
|
||||
Tree t = new Tree();
|
||||
t.setName( "Basic one" );
|
||||
s.persist( f );
|
||||
s.persist( t );
|
||||
tx.commit();
|
||||
s.close();
|
||||
public void testLoading() throws Exception {
|
||||
final Forest created = fromTransaction( (session) -> {
|
||||
Forest f = new Forest();
|
||||
session.persist( f );
|
||||
return f;
|
||||
} );
|
||||
|
||||
s = openSession();
|
||||
tx = s.beginTransaction();
|
||||
f = (Forest) s.load( Forest.class, f.getId() );
|
||||
t = (Tree) s.load( Tree.class, t.getId() );
|
||||
assertFalse( "Default should be lazy", Hibernate.isInitialized( f ) );
|
||||
assertTrue( "Tree is not lazy", Hibernate.isInitialized( t ) );
|
||||
tx.commit();
|
||||
s.close();
|
||||
// getReference
|
||||
inTransaction( (session) -> {
|
||||
final Forest reference = session.getReference( Forest.class, created.getId() );
|
||||
assertFalse( Hibernate.isInitialized( reference ) );
|
||||
} );
|
||||
|
||||
// find
|
||||
inTransaction( (session) -> {
|
||||
final Forest reference = session.find( Forest.class, created.getId() );
|
||||
assertTrue( Hibernate.isInitialized( reference ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -7,19 +7,15 @@
|
|||
|
||||
//$Id$
|
||||
package org.hibernate.orm.test.annotations.entity;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
/**
|
||||
* Non lazy entity
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
public class Tree {
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
//$
|
||||
package org.hibernate.orm.test.annotations.idmanytoone;
|
||||
|
||||
import java.io.Serializable;
|
||||
import jakarta.persistence.Basic;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.IdClass;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
|
@ -21,7 +21,6 @@ import jakarta.persistence.Table;
|
|||
|
||||
@Entity
|
||||
@Table(name="BasketItems")
|
||||
@org.hibernate.annotations.Proxy(lazy=false)
|
||||
@IdClass(BasketItemsPK.class)
|
||||
public class BasketItems implements Serializable {
|
||||
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
|
||||
//$
|
||||
package org.hibernate.orm.test.annotations.idmanytoone;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
|
@ -17,7 +19,6 @@ import jakarta.persistence.Table;
|
|||
|
||||
@Entity
|
||||
@Table(name="Customers")
|
||||
@org.hibernate.annotations.Proxy(lazy=false)
|
||||
public class Customers implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -885167444315163039L;
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
//$
|
||||
package org.hibernate.orm.test.annotations.idmanytoone;
|
||||
|
||||
import java.io.Serializable;
|
||||
import jakarta.persistence.Basic;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.IdClass;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
|
@ -22,7 +22,6 @@ import jakarta.persistence.Table;
|
|||
|
||||
@Entity
|
||||
@Table(name="ShoppingBasket")
|
||||
@org.hibernate.annotations.Proxy(lazy=false)
|
||||
@IdClass(ShoppingBasketsPK.class)
|
||||
public class ShoppingBaskets implements Serializable {
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ import jakarta.persistence.Table;
|
|||
|
||||
@Entity
|
||||
@Inheritance( strategy = InheritanceType.JOINED )
|
||||
@org.hibernate.annotations.Proxy( proxyClass = A.class )
|
||||
@Table( name = "ENTITYA" )
|
||||
public class AImpl implements A {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -11,7 +11,6 @@ import jakarta.persistence.Entity;
|
|||
import jakarta.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@org.hibernate.annotations.Proxy( proxyClass = B.class )
|
||||
@Table( name = "ENTITYB" )
|
||||
public class BImpl extends AImpl implements B {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -20,7 +20,6 @@ import jakarta.persistence.Table;
|
|||
|
||||
@Entity
|
||||
@Inheritance( strategy = InheritanceType.JOINED )
|
||||
@org.hibernate.annotations.Proxy( proxyClass = Z.class )
|
||||
@Table( name = "ENTITYZ" )
|
||||
public class ZImpl implements Z {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
|
|
@ -7,7 +7,6 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
@ -15,6 +14,7 @@ import org.hibernate.testing.orm.junit.JiraKey;
|
|||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -29,7 +29,6 @@ import jakarta.persistence.criteria.CriteriaBuilder;
|
|||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
@ -104,7 +103,11 @@ public class BatchEntityWithDisabledProxyTest {
|
|||
s.getSessionFactory().getCache().evictAllRegions();
|
||||
|
||||
Product product = s.getReference( Product.class, 3 );
|
||||
assertTrue( Hibernate.isInitialized(product) );
|
||||
assertFalse( Hibernate.isInitialized( product) );
|
||||
|
||||
Hibernate.initialize( product );
|
||||
|
||||
assertTrue( Hibernate.isInitialized( product) );
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -137,7 +140,6 @@ public class BatchEntityWithDisabledProxyTest {
|
|||
}
|
||||
|
||||
@Entity(name = "Product")
|
||||
@Proxy(lazy = false)
|
||||
@BatchSize(size = 512)
|
||||
@Cacheable
|
||||
public static class Product {
|
||||
|
|
|
@ -7,7 +7,6 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
|
@ -151,7 +150,6 @@ public class BatchEntityOneToManyWithDisabledProxyTest {
|
|||
|
||||
@Entity(name = "Product")
|
||||
@BatchSize(size = 512)
|
||||
@Proxy(lazy = false)
|
||||
@Cacheable
|
||||
public static class Product {
|
||||
@Id
|
||||
|
|
|
@ -6,7 +6,6 @@ import org.hibernate.Hibernate;
|
|||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
|
@ -183,7 +182,6 @@ public class BatchEntityWithSelectFetchWithDisableProxyTest {
|
|||
@Entity(name = "Product")
|
||||
@BatchSize(size = 512)
|
||||
@Cacheable
|
||||
@Proxy(lazy = false)
|
||||
public static class Product {
|
||||
@Id
|
||||
Long id;
|
||||
|
|
|
@ -5,7 +5,6 @@ import org.hibernate.annotations.Cache;
|
|||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
|
@ -109,7 +108,6 @@ public class AbstractManyToOneNoProxyTest {
|
|||
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
@Proxy(lazy = false)
|
||||
@BatchSize(size = 512)
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@Cacheable
|
||||
|
@ -144,7 +142,6 @@ public class AbstractManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
@BatchSize(size = 512)
|
||||
@DiscriminatorValue(value = "USER")
|
||||
public static class User extends Actor {
|
||||
|
@ -166,7 +163,6 @@ public class AbstractManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
@DiscriminatorValue("USERS")
|
||||
@BatchSize(size = 256)
|
||||
public static class UserGroup extends ActorGroup<User> {
|
||||
|
@ -176,7 +172,6 @@ public class AbstractManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
@Table(name = "actor_group")
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@DiscriminatorColumn(name = "TYPE")
|
||||
|
|
|
@ -5,7 +5,6 @@ import org.hibernate.annotations.Cache;
|
|||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
|
@ -110,7 +109,6 @@ public class ManyToOneNoProxyTest {
|
|||
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
@Proxy(lazy = false)
|
||||
@BatchSize(size = 512)
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@Cacheable
|
||||
|
@ -145,7 +143,6 @@ public class ManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
@BatchSize(size = 512)
|
||||
@DiscriminatorValue(value = "USER")
|
||||
public static class User extends Actor {
|
||||
|
@ -167,7 +164,6 @@ public class ManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
@DiscriminatorValue("USERS")
|
||||
@BatchSize(size = 256)
|
||||
public static class UserGroup extends ActorGroup<User> {
|
||||
|
@ -177,7 +173,6 @@ public class ManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
@Table(name = "actor_group")
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@DiscriminatorColumn(name = "TYPE")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package org.hibernate.orm.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.annotations.ConcreteProxy;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
|
@ -74,9 +74,7 @@ public class LazyAbstractManyToOneNoProxyTest {
|
|||
assertThat( user ).isNotNull();
|
||||
assertThat( user.getName() ).isEqualTo( USER_1_NAME );
|
||||
|
||||
// The User#team type has subclasses so even if it is lazy we need to initialize it because we do not know
|
||||
// the real type and Proxy creation is disabled
|
||||
assertThat( statementInspector.getSqlQueries().size() ).isEqualTo( 2 );
|
||||
assertThat( statementInspector.getSqlQueries().size() ).isEqualTo( 1 );
|
||||
|
||||
statementInspector.clear();
|
||||
|
||||
|
@ -84,14 +82,15 @@ public class LazyAbstractManyToOneNoProxyTest {
|
|||
assertThat( team ).isInstanceOf( UserGroup.class );
|
||||
UserGroup userGroup = (UserGroup) team;
|
||||
assertThat( userGroup.getName() ).isEqualTo( USER_GROUP_1_NAME );
|
||||
assertThat( statementInspector.getSqlQueries().size() ).isEqualTo( 0 );
|
||||
|
||||
// accessing the name
|
||||
assertThat( statementInspector.getSqlQueries().size() ).isEqualTo( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "User")
|
||||
@Table(name = "usr_tbl")
|
||||
@Proxy(lazy = false)
|
||||
public static class User {
|
||||
@Id
|
||||
Long id;
|
||||
|
@ -127,7 +126,7 @@ public class LazyAbstractManyToOneNoProxyTest {
|
|||
@Entity(name = "ActorGroup")
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@DiscriminatorColumn(name = "TYPE")
|
||||
@Proxy(lazy = false)
|
||||
@ConcreteProxy
|
||||
public abstract static class ActorGroup {
|
||||
@Id
|
||||
Long id;
|
||||
|
@ -141,7 +140,6 @@ public class LazyAbstractManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity(name = "UserGroup")
|
||||
@Proxy(lazy = false)
|
||||
@DiscriminatorValue("USERS")
|
||||
public static class UserGroup extends ActorGroup {
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.hibernate.orm.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
@ -85,7 +83,6 @@ public class LazyManyToOneNoProxyTest {
|
|||
|
||||
@Entity(name = "User")
|
||||
@Table(name = "usr_tbl")
|
||||
@Proxy(lazy = false)
|
||||
public static class User {
|
||||
@Id
|
||||
Long id;
|
||||
|
@ -119,7 +116,6 @@ public class LazyManyToOneNoProxyTest {
|
|||
}
|
||||
|
||||
@Entity(name = "UserGroup")
|
||||
@Proxy(lazy = false)
|
||||
public static class UserGroup {
|
||||
@Id
|
||||
Long id;
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.hibernate.Session;
|
|||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
|
@ -18,6 +17,7 @@ import org.hibernate.engine.spi.ManagedEntity;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
@ -227,7 +227,6 @@ public class ByteCodeEnhancedImmutableReferenceCacheTest extends BaseCoreFunctio
|
|||
@Immutable
|
||||
@Cacheable
|
||||
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
|
||||
@Proxy(lazy = false)
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public static class MyEnhancedReferenceData implements ManagedEntity {
|
||||
@Id
|
||||
|
|
|
@ -6,22 +6,20 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.cache;
|
||||
|
||||
import jakarta.persistence.Cacheable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Immutable;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import jakarta.persistence.Cacheable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
@ -91,7 +89,6 @@ public class ReferenceCacheTest extends BaseCoreFunctionalTestCase {
|
|||
@Immutable
|
||||
@Cacheable
|
||||
@Cache( usage = CacheConcurrencyStrategy.READ_ONLY )
|
||||
@Proxy( lazy = false )
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public static class MyReferenceData {
|
||||
@Id
|
||||
|
|
|
@ -1,204 +0,0 @@
|
|||
package org.hibernate.orm.test.caching;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.BatchSize;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.Jira;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Cacheable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.PostLoad;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DomainModel( annotatedClasses = {
|
||||
CachingBatchLoadNoProxiesAndCircularRelationshipTest.Category.class,
|
||||
CachingBatchLoadNoProxiesAndCircularRelationshipTest.CategoryHolder.class,
|
||||
} )
|
||||
@SessionFactory
|
||||
@ServiceRegistry( settings = @Setting( name = AvailableSettings.USE_SECOND_LEVEL_CACHE, value = "true" ) )
|
||||
@Jira( "https://hibernate.atlassian.net/browse/HHH-17918" )
|
||||
@Jira( "https://hibernate.atlassian.net/browse/HHH-17983" )
|
||||
public class CachingBatchLoadNoProxiesAndCircularRelationshipTest {
|
||||
private static final int NUMBER_OF_CATEGORIES = 5;
|
||||
|
||||
@Test
|
||||
public void recursiveBatchLoadingWithCircularRelationship(SessionFactoryScope scope) {
|
||||
// Set the state of the 2nd-level cache, so it contains #1 (and potentially others) but not #0 or #3
|
||||
scope.getSessionFactory().getCache().evict( Category.class );
|
||||
scope.inTransaction( session -> session.getReference( Category.class, 1 ) );
|
||||
scope.getSessionFactory().getCache().evict( Category.class, 0 );
|
||||
scope.getSessionFactory().getCache().evict( Category.class, 3 );
|
||||
|
||||
scope.inSession( session -> {
|
||||
final CategoryHolder result = session.createQuery(
|
||||
"from CategoryHolder where id = 0",
|
||||
CategoryHolder.class
|
||||
).getSingleResult();
|
||||
Category category = result.getLeftCategory();
|
||||
for ( int i = 0; i < NUMBER_OF_CATEGORIES; i++ ) {
|
||||
assertThat( category ).matches( Hibernate::isInitialized, "Category was not initialized" )
|
||||
.extracting( Category::getId )
|
||||
.isEqualTo( i );
|
||||
if ( i == 3 ) {
|
||||
assertThat( category ).isSameAs( result.getRightCategory() );
|
||||
}
|
||||
else if ( i == NUMBER_OF_CATEGORIES - 1 ) {
|
||||
assertThat( category.getNextCategory() ).isSameAs( result.getLeftCategory() );
|
||||
}
|
||||
category = category.getNextCategory();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recursiveBatchLoadingSameQueryTest(SessionFactoryScope scope) {
|
||||
scope.getSessionFactory().getCache().evict( Category.class );
|
||||
scope.inSession( session -> {
|
||||
final CategoryHolder result = session.find( CategoryHolder.class, 1 );
|
||||
Category category = result.getLeftCategory();
|
||||
for ( int i = 0; i < NUMBER_OF_CATEGORIES; i++ ) {
|
||||
assertThat( category ).matches( Hibernate::isInitialized, "Category was not initialized" )
|
||||
.extracting( Category::getId )
|
||||
.isEqualTo( i );
|
||||
if ( i == NUMBER_OF_CATEGORIES - 1 ) {
|
||||
assertThat( category ).isSameAs( result.getRightCategory() );
|
||||
assertThat( category.getNextCategory() ).isSameAs( result.getLeftCategory() );
|
||||
}
|
||||
category = category.getNextCategory();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public void setupEntities(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
final Category[] categories = new Category[NUMBER_OF_CATEGORIES];
|
||||
for ( int i = 0; i < categories.length; i++ ) {
|
||||
categories[i] = new Category( i, "category_" + i );
|
||||
session.persist( categories[i] );
|
||||
}
|
||||
// Chain-link the categories (#n points to #n+1, last one points to #0)
|
||||
for ( int i = 0; i < categories.length - 1; i++ ) {
|
||||
categories[i].setNextCategory( categories[i + 1] );
|
||||
}
|
||||
categories[categories.length - 1].nextCategory = categories[0];
|
||||
final CategoryHolder holder1 = new CategoryHolder( 0 );
|
||||
holder1.leftCategory = categories[0];
|
||||
holder1.rightCategory = categories[3];
|
||||
session.persist( holder1 );
|
||||
final CategoryHolder holder2 = new CategoryHolder( 1 );
|
||||
holder2.leftCategory = categories[0];
|
||||
holder2.rightCategory = categories[4];
|
||||
session.persist( holder2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
session.createMutationQuery( "delete from CategoryHolder" ).executeUpdate();
|
||||
session.createQuery( "from Category", Category.class )
|
||||
.getResultList()
|
||||
.forEach( c -> c.setNextCategory( null ) );
|
||||
session.createMutationQuery( "delete from Category" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
@Proxy( lazy = false )
|
||||
@Entity( name = "Category" )
|
||||
@BatchSize( size = 10 )
|
||||
@Cacheable
|
||||
@Cache( usage = CacheConcurrencyStrategy.READ_WRITE )
|
||||
static class Category {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne( fetch = FetchType.LAZY )
|
||||
@Fetch( value = FetchMode.SELECT )
|
||||
private Category nextCategory;
|
||||
|
||||
public Category() {
|
||||
}
|
||||
|
||||
public Category(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Category getNextCategory() {
|
||||
return nextCategory;
|
||||
}
|
||||
|
||||
public void setNextCategory(Category nextCategory) {
|
||||
this.nextCategory = nextCategory;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@PostLoad
|
||||
public void postLoad() {
|
||||
assertThat( name ).isNotNull().isEqualTo( "category_" + id );
|
||||
assertThat( nextCategory.getId() ).isNotNull();
|
||||
// note : nextCategory.name will be null here since the instance will not have been initialized yet
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "CategoryHolder" )
|
||||
static class CategoryHolder {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne( fetch = FetchType.LAZY )
|
||||
@Fetch( value = FetchMode.SELECT )
|
||||
private Category leftCategory;
|
||||
|
||||
@ManyToOne( fetch = FetchType.LAZY )
|
||||
@Fetch( value = FetchMode.SELECT )
|
||||
private Category rightCategory;
|
||||
|
||||
public CategoryHolder() {
|
||||
}
|
||||
|
||||
public CategoryHolder(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Category getLeftCategory() {
|
||||
return leftCategory;
|
||||
}
|
||||
|
||||
public Category getRightCategory() {
|
||||
return rightCategory;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* 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.orm.test.classloader;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests if instrumentation is done with the proper classloader for entities with proxy class. The classloader
|
||||
* of {@link HibernateProxy} will not see {@link IPerson}, since it is only accessible from this package. But: the
|
||||
* classloader of {@link IPerson} will see {@link HibernateProxy}, so instrumentation will only work if this classloader
|
||||
* is chosen for creating the instrumented proxy class. We need to check the class of a loaded object though, since
|
||||
* building the configuration will not fail, only log the error and fall back to using the entity class itself as a
|
||||
* proxy.
|
||||
*
|
||||
* @author lgathy
|
||||
*/
|
||||
public class ProxyInterfaceClassLoaderTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Person.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyClassLoader() {
|
||||
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
IPerson p = new Person();
|
||||
p.setId( 1 );
|
||||
s.persist( p );
|
||||
s.flush();
|
||||
s.clear();
|
||||
|
||||
Object lp = s.load( Person.class, p.getId() );
|
||||
|
||||
Assert.assertTrue( "Loaded entity is not an instance of the proxy interface", IPerson.class.isInstance( lp ) );
|
||||
Assert.assertFalse( "Proxy class was not created", Person.class.isInstance( lp ) );
|
||||
|
||||
s.remove( lp );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public interface IPerson {
|
||||
|
||||
int getId();
|
||||
|
||||
void setId(int id);
|
||||
|
||||
}
|
||||
|
||||
@Entity( name = "Person" )
|
||||
@Proxy(proxyClass = IPerson.class)
|
||||
static class Person implements IPerson {
|
||||
|
||||
@Id
|
||||
private int id;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -8,84 +8,55 @@ package org.hibernate.orm.test.fetchstrategyhelper;
|
|||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.internal.FetchOptionsHelper;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.sql.results.graph.FetchOptions;
|
||||
import org.hibernate.type.AssociationType;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public class NoProxyFetchStrategyHelperTest extends BaseCoreFunctionalTestCase {
|
||||
public class FetchStrategyDeterminationTests extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Test
|
||||
public void testManyToOneDefaultFetch() {
|
||||
final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntityDefault" );
|
||||
final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntityDefault" );
|
||||
assertSame( org.hibernate.FetchMode.JOIN, fetchMode );
|
||||
final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata(
|
||||
fetchMode,
|
||||
associationType,
|
||||
sessionFactory()
|
||||
);
|
||||
assertSame( FetchStyle.JOIN, fetchStyle );
|
||||
final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming(
|
||||
fetchStyle,
|
||||
associationType,
|
||||
sessionFactory()
|
||||
);
|
||||
assertSame( FetchTiming.IMMEDIATE, fetchTiming );
|
||||
final EntityPersister entityDescriptor = sessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class );
|
||||
final AttributeMapping attributeMapping = entityDescriptor.findAttributeMapping( "otherEntityDefault" );
|
||||
final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions();
|
||||
assertEquals( mappedFetchOptions.getTiming(), FetchTiming.IMMEDIATE );
|
||||
assertEquals( mappedFetchOptions.getStyle(), FetchStyle.JOIN );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyToOneJoinFetch() {
|
||||
final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntityJoin" );
|
||||
final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntityJoin" );
|
||||
assertSame( org.hibernate.FetchMode.JOIN, fetchMode );
|
||||
final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata(
|
||||
fetchMode,
|
||||
associationType,
|
||||
sessionFactory()
|
||||
);
|
||||
assertSame( FetchStyle.JOIN, fetchStyle );
|
||||
final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming(
|
||||
fetchStyle,
|
||||
associationType,
|
||||
sessionFactory()
|
||||
);
|
||||
assertSame( FetchTiming.IMMEDIATE, fetchTiming );
|
||||
final EntityPersister entityDescriptor = sessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class );
|
||||
final AttributeMapping attributeMapping = entityDescriptor.findAttributeMapping( "otherEntityJoin" );
|
||||
final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions();
|
||||
assertEquals( mappedFetchOptions.getTiming(), FetchTiming.IMMEDIATE );
|
||||
assertEquals( mappedFetchOptions.getStyle(), FetchStyle.JOIN );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManyToOneSelectFetch() {
|
||||
final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntitySelect" );
|
||||
final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntitySelect" );
|
||||
assertSame( org.hibernate.FetchMode.SELECT, fetchMode );
|
||||
final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata(
|
||||
fetchMode,
|
||||
associationType,
|
||||
sessionFactory()
|
||||
);
|
||||
assertSame( FetchStyle.SELECT, fetchStyle );
|
||||
final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming(
|
||||
fetchStyle,
|
||||
associationType,
|
||||
sessionFactory()
|
||||
);
|
||||
// Proxies are not allowed, so it should be FetchTiming.IMMEDIATE
|
||||
assertSame( FetchTiming.IMMEDIATE, fetchTiming );
|
||||
final EntityPersister entityDescriptor = sessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class );
|
||||
final AttributeMapping attributeMapping = entityDescriptor.findAttributeMapping( "otherEntitySelect" );
|
||||
final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions();
|
||||
assertEquals( mappedFetchOptions.getTiming(), FetchTiming.IMMEDIATE );
|
||||
assertEquals( mappedFetchOptions.getStyle(), FetchStyle.SELECT );
|
||||
}
|
||||
|
||||
private org.hibernate.FetchMode determineFetchMode(Class<?> entityClass, String path) {
|
||||
|
@ -108,7 +79,7 @@ public class NoProxyFetchStrategyHelperTest extends BaseCoreFunctionalTestCase {
|
|||
OtherEntity.class
|
||||
};
|
||||
}
|
||||
@jakarta.persistence.Entity
|
||||
@Entity
|
||||
@Table(name="entity")
|
||||
public static class AnEntity {
|
||||
@Id
|
||||
|
@ -129,9 +100,8 @@ public class NoProxyFetchStrategyHelperTest extends BaseCoreFunctionalTestCase {
|
|||
// @Fetch(FetchMode.SUBSELECT) is not allowed for ToOne associations
|
||||
}
|
||||
|
||||
@jakarta.persistence.Entity
|
||||
@Entity
|
||||
@Table(name="otherentity")
|
||||
@Proxy(lazy = false)
|
||||
public static class OtherEntity {
|
||||
@Id
|
||||
@GeneratedValue
|
|
@ -9,6 +9,10 @@
|
|||
package org.hibernate.orm.test.jpa.cascade;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
|
@ -17,17 +21,12 @@ import jakarta.persistence.JoinColumn;
|
|||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
/**
|
||||
* @author Emmanuel Bernard
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "portal_pk_docs_extraction")
|
||||
@DynamicUpdate @DynamicInsert
|
||||
@Proxy
|
||||
public class ExtractionDocument implements Serializable {
|
||||
private Long id;
|
||||
private byte[] body;
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/*
|
||||
* 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.orm.test.ops.genericApi;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = ProxiedGetLoadAccessTest.UserImpl.class
|
||||
)
|
||||
@SessionFactory
|
||||
public class ProxiedGetLoadAccessTest {
|
||||
|
||||
@Test
|
||||
public void testIt(SessionFactoryScope scope) {
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// create a row
|
||||
scope.inTransaction(
|
||||
session ->
|
||||
session.persist( new UserImpl( "steve" ) )
|
||||
);
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// test `get` access
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// THis technically works
|
||||
session.get( UserImpl.class, 1 );
|
||||
session.get( User.class, 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.get( UserImpl.class, 1, LockMode.PESSIMISTIC_WRITE );
|
||||
session.get( User.class, 1, LockMode.PESSIMISTIC_WRITE );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.get( UserImpl.class, 1, LockOptions.UPGRADE );
|
||||
session.get( User.class, 1, LockOptions.UPGRADE );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.byId( UserImpl.class ).load( 1 );
|
||||
session.byId( User.class ).load( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.byId( UserImpl.class ).with( LockOptions.UPGRADE ).load( 1 );
|
||||
session.byId( User.class ).with( LockOptions.UPGRADE ).load( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// test `load` access
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.load( UserImpl.class, 1 );
|
||||
session.load( User.class, 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.load( UserImpl.class, 1, LockMode.PESSIMISTIC_WRITE );
|
||||
session.load( User.class, 1, LockMode.PESSIMISTIC_WRITE );
|
||||
}
|
||||
);
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.load( UserImpl.class, 1, LockOptions.UPGRADE );
|
||||
session.load( User.class, 1, LockOptions.UPGRADE );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.byId( UserImpl.class ).getReference( 1 );
|
||||
session.byId( User.class ).getReference( 1 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.byId( UserImpl.class ).with( LockOptions.UPGRADE ).getReference( 1 );
|
||||
session.byId( User.class ).with( LockOptions.UPGRADE ).getReference( 1 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public interface User {
|
||||
Integer getId();
|
||||
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
}
|
||||
|
||||
@Entity(name = "User")
|
||||
@Table(name = "my_user")
|
||||
@Proxy(proxyClass = User.class)
|
||||
public static class UserImpl implements User {
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public UserImpl() {
|
||||
}
|
||||
|
||||
public UserImpl(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue(generator = "increment")
|
||||
@GenericGenerator(name = "increment", strategy = "increment")
|
||||
@Override
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* 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.orm.test.proxy;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author lgathy
|
||||
*/
|
||||
public class ProxyInterfaceTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Book.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProxyClassLoader() {
|
||||
|
||||
//tag::entity-proxy-persist-mapping[]
|
||||
doInHibernate(this::sessionFactory, session -> {
|
||||
Book book = new Book();
|
||||
book.setId(1L);
|
||||
book.setTitle("High-Performance Java Persistence");
|
||||
book.setAuthor("Vlad Mihalcea");
|
||||
|
||||
session.persist(book);
|
||||
});
|
||||
|
||||
doInHibernate(this::sessionFactory, session -> {
|
||||
Identifiable book = session.getReference(Book.class, 1L);
|
||||
|
||||
assertTrue(
|
||||
"Loaded entity is not an instance of the proxy interface",
|
||||
book instanceof Identifiable
|
||||
);
|
||||
assertFalse(
|
||||
"Proxy class was not created",
|
||||
book instanceof Book
|
||||
);
|
||||
});
|
||||
//end::entity-proxy-persist-mapping[]
|
||||
}
|
||||
|
||||
//tag::entity-proxy-interface-mapping[]
|
||||
public interface Identifiable {
|
||||
|
||||
Long getId();
|
||||
|
||||
void setId(Long id);
|
||||
}
|
||||
|
||||
@Entity(name = "Book")
|
||||
@Proxy(proxyClass = Identifiable.class)
|
||||
public static final class Book implements Identifiable {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
private String author;
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
//Other getters and setters omitted for brevity
|
||||
//end::entity-proxy-interface-mapping[]
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(String author) {
|
||||
this.author = author;
|
||||
}
|
||||
//tag::entity-proxy-interface-mapping[]
|
||||
}
|
||||
//end::entity-proxy-interface-mapping[]
|
||||
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
package org.hibernate.orm.test.proxy;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Oliver Henlich
|
||||
*/
|
||||
/**
|
||||
* Test that demonstrates the intermittent {@link ClassCastException} that occurs
|
||||
* when trying to call a method on a {@link HibernateProxy} where the parameter
|
||||
* type is defined by generics.
|
||||
*/
|
||||
@JiraKey("HHH-17578")
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
ProxyWithGenericsTest.AbstractEntityImpl.class,
|
||||
ProxyWithGenericsTest.AbstractShapeEntityImpl.class,
|
||||
ProxyWithGenericsTest.CircleEntityImpl.class,
|
||||
ProxyWithGenericsTest.SquareEntityImpl.class,
|
||||
ProxyWithGenericsTest.CircleContainerEntityImpl.class,
|
||||
ProxyWithGenericsTest.SquareContainerEntityImpl.class,
|
||||
ProxyWithGenericsTest.MainEntityImpl.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@SuppressWarnings("ALL")
|
||||
public class ProxyWithGenericsTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(session -> {
|
||||
EntityManager em = session.unwrap(EntityManager.class);
|
||||
|
||||
// Shape 1
|
||||
CircleEntityImpl cirlce1 = new CircleEntityImpl();
|
||||
cirlce1.radius = BigDecimal.valueOf(1);
|
||||
em.persist(cirlce1);
|
||||
|
||||
// Shape 2
|
||||
SquareEntityImpl square1 = new SquareEntityImpl();
|
||||
square1.width = BigDecimal.valueOf(1);
|
||||
square1.height = BigDecimal.valueOf(2);
|
||||
em.persist(square1);
|
||||
|
||||
// Container 1
|
||||
CircleContainerEntity circleContainer1 = new CircleContainerEntityImpl();
|
||||
em.persist(circleContainer1);
|
||||
|
||||
// Container 2
|
||||
SquareContainerEntity squareContainer1 = new SquareContainerEntityImpl();
|
||||
em.persist(squareContainer1);
|
||||
|
||||
// Main
|
||||
MainEntityImpl main = new MainEntityImpl();
|
||||
main.circleContainer = circleContainer1;
|
||||
main.squareContainer = squareContainer1;
|
||||
em.persist(main);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void test(SessionFactoryScope scope) throws Exception {
|
||||
|
||||
scope.inTransaction(session -> {
|
||||
EntityManager em = session.unwrap(EntityManager.class);
|
||||
|
||||
MainEntityImpl main = em.find(MainEntityImpl.class, 1L);
|
||||
assertNotNull(main);
|
||||
|
||||
CircleContainerEntity circleContainer = main.getCircleContainer();
|
||||
assertNotNull(circleContainer);
|
||||
assertTrue(circleContainer instanceof HibernateProxy);
|
||||
CircleEntity circle1 = em.find(CircleEntityImpl.class, 1L);
|
||||
circleContainer.add(circle1); // This method fails with ClassCastException without the fix
|
||||
|
||||
SquareContainerEntity squareContainer = main.getSquareContainer();
|
||||
assertNotNull(squareContainer);
|
||||
assertTrue(squareContainer instanceof HibernateProxy);
|
||||
SquareEntity square1 = em.find(SquareEntityImpl.class, 2L);
|
||||
squareContainer.add(square1); // This method fails with ClassCastException without the fix
|
||||
});
|
||||
}
|
||||
|
||||
// Shapes hierarchy -------------------------------------------------------
|
||||
public interface ShapeEntity {
|
||||
BigDecimal getArea();
|
||||
}
|
||||
|
||||
public interface CircleEntity extends ShapeEntity {
|
||||
BigDecimal getRadius();
|
||||
}
|
||||
|
||||
public interface SquareEntity extends ShapeEntity {
|
||||
BigDecimal getWidth();
|
||||
|
||||
BigDecimal getHeight();
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
@Access(AccessType.FIELD)
|
||||
public static abstract class AbstractEntityImpl {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Column(name = "ID")
|
||||
Long id;
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "SHAPE")
|
||||
@Access(AccessType.FIELD)
|
||||
@Proxy(proxyClass = ShapeEntity.class)
|
||||
@DiscriminatorColumn(name = "TYPE", length = 20)
|
||||
public static abstract class AbstractShapeEntityImpl
|
||||
extends AbstractEntityImpl
|
||||
implements ShapeEntity {
|
||||
public abstract BigDecimal getArea();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(proxyClass = CircleEntity.class)
|
||||
@Access(AccessType.FIELD)
|
||||
@DiscriminatorValue("CIRCLE")
|
||||
public static class CircleEntityImpl
|
||||
extends AbstractShapeEntityImpl
|
||||
implements CircleEntity {
|
||||
@Column(name = "RADIUS", nullable = true)
|
||||
private BigDecimal radius;
|
||||
|
||||
@Override
|
||||
public BigDecimal getArea() {
|
||||
return new BigDecimal(Math.PI).multiply(radius.pow(2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getRadius() {
|
||||
return radius;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(proxyClass = SquareEntity.class)
|
||||
@Access(AccessType.FIELD)
|
||||
@DiscriminatorValue("SQUARE")
|
||||
public static class SquareEntityImpl
|
||||
extends AbstractShapeEntityImpl
|
||||
implements SquareEntity {
|
||||
|
||||
@Column(name = "WIDTH", nullable = true)
|
||||
private BigDecimal width;
|
||||
|
||||
@Column(name = "HEIGHT", nullable = true)
|
||||
private BigDecimal height;
|
||||
|
||||
@Override
|
||||
public BigDecimal getArea() {
|
||||
return width.multiply(height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getHeight() {
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
// ShapeContainer hierarchy -----------------------------------------------
|
||||
|
||||
public interface ShapeContainerEntity<T extends ShapeEntity> {
|
||||
void add(T shape);
|
||||
}
|
||||
|
||||
public interface CircleContainerEntity extends ShapeContainerEntity<CircleEntity> {
|
||||
|
||||
}
|
||||
|
||||
public interface SquareContainerEntity extends ShapeContainerEntity<SquareEntity> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "CONTAINER")
|
||||
@Access(AccessType.FIELD)
|
||||
@Proxy(proxyClass = ShapeContainerEntity.class)
|
||||
@DiscriminatorColumn(name = "TYPE", length = 20)
|
||||
public static abstract class AbstractShapeContainerEntityImpl<T extends ShapeEntity>
|
||||
extends AbstractEntityImpl
|
||||
implements ShapeContainerEntity<T> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Entity
|
||||
@Proxy(proxyClass = SquareContainerEntity.class)
|
||||
@Access(AccessType.FIELD)
|
||||
@DiscriminatorValue("SQUARE")
|
||||
public static class SquareContainerEntityImpl
|
||||
extends AbstractShapeContainerEntityImpl<SquareEntity>
|
||||
implements SquareContainerEntity {
|
||||
|
||||
@Override
|
||||
public void add(SquareEntity shape) {
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Proxy(proxyClass = CircleContainerEntity.class)
|
||||
@Access(AccessType.FIELD)
|
||||
@DiscriminatorValue("CIRCLE")
|
||||
public static class CircleContainerEntityImpl
|
||||
extends AbstractShapeContainerEntityImpl<CircleEntity>
|
||||
implements CircleContainerEntity {
|
||||
|
||||
@Override
|
||||
public void add(CircleEntity shape) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main test entity that has lazy references to the two types of {@link ShapeContainerEntity containers}.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "Main")
|
||||
@Access(AccessType.FIELD)
|
||||
public static class MainEntityImpl
|
||||
extends AbstractEntityImpl {
|
||||
|
||||
@ManyToOne(targetEntity = AbstractShapeContainerEntityImpl.class, optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "CIRCLE_CONTAINER_ID")
|
||||
private CircleContainerEntity circleContainer;
|
||||
|
||||
@ManyToOne(targetEntity = AbstractShapeContainerEntityImpl.class, optional = true, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "SQUARE_CONTAINER_ID")
|
||||
private SquareContainerEntity squareContainer;
|
||||
|
||||
public CircleContainerEntity getCircleContainer() {
|
||||
return circleContainer;
|
||||
}
|
||||
|
||||
public SquareContainerEntity getSquareContainer() {
|
||||
return squareContainer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,20 +7,19 @@
|
|||
package org.hibernate.orm.test.envers.entities;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "STR_TEST_NP")
|
||||
@Proxy(lazy = false)
|
||||
public class StrTestNoProxyEntity implements Serializable {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.envers.entities.onetoone;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.NotAudited;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
|
@ -13,16 +16,11 @@ import jakarta.persistence.Id;
|
|||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.envers.Audited;
|
||||
import org.hibernate.envers.NotAudited;
|
||||
|
||||
/**
|
||||
* Test class for issue HHH-3854. Restricting creation of proxy objects is essential.
|
||||
*/
|
||||
@Entity
|
||||
@Audited
|
||||
@Proxy(lazy = false)
|
||||
// Class name is too long of an identifier for Oracle.
|
||||
@Table(name = "EdOneToOne")
|
||||
public final class BidirectionalEagerAnnotationRefEdOneToOne {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.envers.entities.onetoone;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
|
@ -15,15 +17,11 @@ import jakarta.persistence.JoinColumn;
|
|||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.Proxy;
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* Test class for issue HHH-3854. Restricting creation of proxy objects is essential.
|
||||
*/
|
||||
@Entity
|
||||
@Audited
|
||||
@Proxy(lazy = false)
|
||||
//Class name is too long of an identifier for Oracle.
|
||||
@Table(name = "IngOneToOne")
|
||||
public final class BidirectionalEagerAnnotationRefIngOneToOne {
|
||||
|
|
|
@ -30,13 +30,9 @@ public class AccountNotAuditedOwners implements Serializable {
|
|||
|
||||
private String type;
|
||||
|
||||
@OneToOne(mappedBy = "account", optional = false)
|
||||
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
|
||||
private NotAuditedNoProxyPerson owner;
|
||||
|
||||
@OneToOne(mappedBy = "account", optional = false, fetch = FetchType.LAZY)
|
||||
@Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
|
||||
private NotAuditedProxyPerson coOwner;
|
||||
private NotAuditedPerson owner;
|
||||
|
||||
public AccountNotAuditedOwners() {
|
||||
}
|
||||
|
@ -91,22 +87,14 @@ public class AccountNotAuditedOwners implements Serializable {
|
|||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public NotAuditedNoProxyPerson getOwner() {
|
||||
public NotAuditedPerson getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(NotAuditedNoProxyPerson owner) {
|
||||
public void setOwner(NotAuditedPerson owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public NotAuditedProxyPerson getCoOwner() {
|
||||
return coOwner;
|
||||
}
|
||||
|
||||
public void setCoOwner(NotAuditedProxyPerson coOwner) {
|
||||
this.coOwner = coOwner;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
package org.hibernate.orm.test.envers.integration.onetoone.bidirectional.primarykeyjoincolumn;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
|
@ -14,15 +18,10 @@ import jakarta.persistence.Id;
|
|||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
/**
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Entity
|
||||
@Proxy(lazy = false)
|
||||
public class NotAuditedNoProxyPerson implements Serializable {
|
||||
@Id
|
||||
@Column(name = "PERSON_ID")
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
package org.hibernate.orm.test.envers.integration.onetoone.bidirectional.primarykeyjoincolumn;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
|
@ -15,16 +19,11 @@ import jakarta.persistence.Id;
|
|||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
/**
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
@Entity
|
||||
@Proxy(lazy = true)
|
||||
public class NotAuditedProxyPerson implements Serializable {
|
||||
public class NotAuditedPerson implements Serializable {
|
||||
@Id
|
||||
@Column(name = "PERSON_ID")
|
||||
@GeneratedValue(generator = "NotAuditedProxyKeyGenerator")
|
||||
|
@ -38,14 +37,14 @@ public class NotAuditedProxyPerson implements Serializable {
|
|||
@PrimaryKeyJoinColumn(name = "PERSON_ID", referencedColumnName = "ACCOUNT_ID")
|
||||
private AccountNotAuditedOwners account;
|
||||
|
||||
public NotAuditedProxyPerson() {
|
||||
public NotAuditedPerson() {
|
||||
}
|
||||
|
||||
public NotAuditedProxyPerson(String name) {
|
||||
public NotAuditedPerson(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NotAuditedProxyPerson(Long personId, String name) {
|
||||
public NotAuditedPerson(Long personId, String name) {
|
||||
this.personId = personId;
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -55,11 +54,11 @@ public class NotAuditedProxyPerson implements Serializable {
|
|||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( !(o instanceof NotAuditedProxyPerson) ) {
|
||||
if ( !(o instanceof NotAuditedPerson ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NotAuditedProxyPerson person = (NotAuditedProxyPerson) o;
|
||||
NotAuditedPerson person = (NotAuditedPerson) o;
|
||||
|
||||
if ( personId != null ? !personId.equals( person.personId ) : person.personId != null ) {
|
||||
return false;
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.orm.test.envers.integration.onetoone.bidirectional.primarykeyjoincolumn;
|
||||
|
||||
import java.util.Arrays;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.hibernate.envers.RevisionType;
|
||||
import org.hibernate.envers.query.AuditEntity;
|
||||
|
@ -19,6 +18,8 @@ import org.hibernate.testing.TestForIssue;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
*/
|
||||
|
@ -27,7 +28,6 @@ public class OneToOneWithPrimaryKeyJoinTest extends BaseEnversJPAFunctionalTestC
|
|||
private Long personId = null;
|
||||
private Long accountId = null;
|
||||
private Long proxyPersonId = null;
|
||||
private Long noProxyPersonId = null;
|
||||
private Long accountNotAuditedOwnersId = null;
|
||||
|
||||
@Override
|
||||
|
@ -36,8 +36,7 @@ public class OneToOneWithPrimaryKeyJoinTest extends BaseEnversJPAFunctionalTestC
|
|||
Person.class,
|
||||
Account.class,
|
||||
AccountNotAuditedOwners.class,
|
||||
NotAuditedNoProxyPerson.class,
|
||||
NotAuditedProxyPerson.class
|
||||
NotAuditedPerson.class
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -58,15 +57,11 @@ public class OneToOneWithPrimaryKeyJoinTest extends BaseEnversJPAFunctionalTestC
|
|||
|
||||
// Revision 2
|
||||
em.getTransaction().begin();
|
||||
NotAuditedNoProxyPerson noProxyPerson = new NotAuditedNoProxyPerson( "Kinga" );
|
||||
NotAuditedProxyPerson proxyPerson = new NotAuditedProxyPerson( "Lukasz" );
|
||||
NotAuditedPerson proxyPerson = new NotAuditedPerson( "Lukasz" );
|
||||
AccountNotAuditedOwners accountNotAuditedOwners = new AccountNotAuditedOwners( "Standard" );
|
||||
noProxyPerson.setAccount( accountNotAuditedOwners );
|
||||
proxyPerson.setAccount( accountNotAuditedOwners );
|
||||
accountNotAuditedOwners.setOwner( noProxyPerson );
|
||||
accountNotAuditedOwners.setCoOwner( proxyPerson );
|
||||
accountNotAuditedOwners.setOwner( proxyPerson );
|
||||
em.persist( accountNotAuditedOwners );
|
||||
em.persist( noProxyPerson );
|
||||
em.persist( proxyPerson );
|
||||
em.getTransaction().commit();
|
||||
|
||||
|
@ -74,7 +69,6 @@ public class OneToOneWithPrimaryKeyJoinTest extends BaseEnversJPAFunctionalTestC
|
|||
accountId = account.getAccountId();
|
||||
accountNotAuditedOwnersId = accountNotAuditedOwners.getAccountId();
|
||||
proxyPersonId = proxyPerson.getPersonId();
|
||||
noProxyPersonId = noProxyPerson.getPersonId();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -127,16 +121,13 @@ public class OneToOneWithPrimaryKeyJoinTest extends BaseEnversJPAFunctionalTestC
|
|||
|
||||
@Test
|
||||
public void testHistoryOfAccountNotAuditedOwners() {
|
||||
NotAuditedNoProxyPerson noProxyPersonVer1 = new NotAuditedNoProxyPerson( noProxyPersonId, "Kinga" );
|
||||
NotAuditedProxyPerson proxyPersonVer1 = new NotAuditedProxyPerson( proxyPersonId, "Lukasz" );
|
||||
NotAuditedPerson proxyPersonVer1 = new NotAuditedPerson( proxyPersonId, "Lukasz" );
|
||||
AccountNotAuditedOwners accountNotAuditedOwnersVer1 = new AccountNotAuditedOwners(
|
||||
accountNotAuditedOwnersId,
|
||||
"Standard"
|
||||
);
|
||||
noProxyPersonVer1.setAccount( accountNotAuditedOwnersVer1 );
|
||||
proxyPersonVer1.setAccount( accountNotAuditedOwnersVer1 );
|
||||
accountNotAuditedOwnersVer1.setOwner( noProxyPersonVer1 );
|
||||
accountNotAuditedOwnersVer1.setCoOwner( proxyPersonVer1 );
|
||||
accountNotAuditedOwnersVer1.setOwner( proxyPersonVer1 );
|
||||
|
||||
Object[] result = ((Object[]) getAuditReader().createQuery()
|
||||
.forRevisionsOfEntity( AccountNotAuditedOwners.class, false, true )
|
||||
|
@ -146,13 +137,10 @@ public class OneToOneWithPrimaryKeyJoinTest extends BaseEnversJPAFunctionalTestC
|
|||
|
||||
Assert.assertEquals( accountNotAuditedOwnersVer1, result[0] );
|
||||
Assert.assertEquals( RevisionType.ADD, result[2] );
|
||||
// Checking non-proxy reference
|
||||
Assert.assertEquals( accountNotAuditedOwnersVer1.getOwner(), ((AccountNotAuditedOwners) result[0]).getOwner() );
|
||||
// Checking proxy reference
|
||||
Assert.assertTrue( ((AccountNotAuditedOwners) result[0]).getCoOwner() instanceof HibernateProxy );
|
||||
Assert.assertTrue( ((AccountNotAuditedOwners) result[0]).getOwner() instanceof HibernateProxy );
|
||||
Assert.assertEquals(
|
||||
proxyPersonVer1.getPersonId(),
|
||||
((AccountNotAuditedOwners) result[0]).getCoOwner().getPersonId()
|
||||
((AccountNotAuditedOwners) result[0]).getOwner().getPersonId()
|
||||
);
|
||||
|
||||
Assert.assertEquals(
|
||||
|
|
|
@ -115,6 +115,26 @@ String isDefault();
|
|||
----
|
||||
|
||||
|
||||
[[proxy-annotation]]
|
||||
== Replace @Proxy
|
||||
|
||||
Applications will need to replace usages of the removed `@Proxy` annotation.
|
||||
|
||||
`@Proxy#proxyClass` has no direct replacement, but was also never needed/useful.
|
||||
|
||||
Here we focus on `@Proxy#laxy` attribute which, again, was hardly ever useful.
|
||||
By default (true), Hibernate would proxy an entity when possible and when asked for.
|
||||
"Asked for" includes calls to `Session#getReference` and lazy associations.
|
||||
All such cases though are already controllable by the application.
|
||||
|
||||
* Instead of `Session#getReference`, use `Session#find`
|
||||
* Use eager associations, using
|
||||
** `FetchType.EAGER` (the default for to-one associations anyway), possibly combined with `@Fetch`
|
||||
** `EntityGraph`
|
||||
** `@FetchProfiles`
|
||||
|
||||
The effect can also often be mitigated using Hibernate's bytecode-based laziness (possibly combined with `@ConcreteProxy`).
|
||||
|
||||
|
||||
[[flush-persist]]
|
||||
== Session flush and persist
|
||||
|
|
Loading…
Reference in New Issue