HHH-13658 : make NO_PROXY unnecessary
- Better handle `FetchModeType#LAZY` for to-one associations based on whether bytecode-enhancement-as-proxy is enabled. Minimize the cases a user is likely to need to use `@LazyToOne` - See also EAP7-1402
This commit is contained in:
parent
949ba3b083
commit
0c974991f7
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.mapping.lazytoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity( name = "Airport" )
|
||||
@Table( name = "airport" )
|
||||
public class Airport {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String code;
|
||||
|
||||
public Airport() {
|
||||
}
|
||||
|
||||
public Airport(Integer id, String code) {
|
||||
this.id = id;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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.mapping.lazytoone;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
|
||||
import static javax.persistence.FetchType.LAZY;
|
||||
import static org.hibernate.annotations.LazyToOneOption.NO_PROXY;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity( name = "Flight" )
|
||||
@Table( name = "flight" )
|
||||
public class Flight {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String number;
|
||||
|
||||
@ManyToOne( fetch = LAZY )
|
||||
private Airport origination;
|
||||
|
||||
@ManyToOne( fetch = LAZY )
|
||||
@LazyToOne( NO_PROXY )
|
||||
private Airport destination;
|
||||
|
||||
public Flight() {
|
||||
}
|
||||
|
||||
public Flight(Integer id, String number) {
|
||||
this.id = id;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Flight(Integer id, String number, Airport origination, Airport destination) {
|
||||
this.id = id;
|
||||
this.number = number;
|
||||
this.origination = origination;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Airport getOrigination() {
|
||||
return origination;
|
||||
}
|
||||
|
||||
public void setOrigination(Airport origination) {
|
||||
this.origination = origination;
|
||||
}
|
||||
|
||||
public Airport getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(Airport destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.mapping.lazytoone;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.FailureExpected;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Same as {@link LazyToOneTest} except here we have bytecode-enhanced entities
|
||||
* via {@link BytecodeEnhancerRunner}
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class InstrumentedLazyToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Airport.class, Flight.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Airport austin = new Airport( 1, "AUS" );
|
||||
final Airport baltimore = new Airport( 2, "BWI" );
|
||||
|
||||
final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore );
|
||||
final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin );
|
||||
|
||||
session.persist( austin );
|
||||
session.persist( baltimore );
|
||||
|
||||
session.persist( flight1 );
|
||||
session.persist( flight2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTestData() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Flight" ).executeUpdate();
|
||||
session.createQuery( "delete Airport" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected( jiraKey = "HHH-13658", message = "Flight#origination is not treated as lazy. Not sure why exactly" )
|
||||
public void testEnhancedButProxyNotAllowed() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
statistics.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Flight flight1 = session.byId( Flight.class ).load( 1 );
|
||||
|
||||
// unlike the other 2 tests we should get 2 db queries here
|
||||
assertThat( statistics.getPrepareStatementCount(), is( 2L ) );
|
||||
|
||||
assertThat( Hibernate.isInitialized( flight1 ), is( true ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) );
|
||||
// this should be a non-enhanced proxy
|
||||
assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( false ) );
|
||||
// the NO_PROXY here should trigger an EAGER load
|
||||
assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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.mapping.lazytoone;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Same as {@link InstrumentedLazyToOneTest} except here we enable bytecode-enhanced proxies
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class InstrumentedProxyLazyToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Airport.class, Flight.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Airport austin = new Airport( 1, "AUS" );
|
||||
final Airport baltimore = new Airport( 2, "BWI" );
|
||||
|
||||
final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore );
|
||||
final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin );
|
||||
|
||||
session.persist( austin );
|
||||
session.persist( baltimore );
|
||||
|
||||
session.persist( flight1 );
|
||||
session.persist( flight2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTestData() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Flight" ).executeUpdate();
|
||||
session.createQuery( "delete Airport" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhancedWithProxy() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
statistics.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Flight flight1 = session.byId( Flight.class ).load( 1 );
|
||||
|
||||
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
||||
|
||||
assertThat( Hibernate.isInitialized( flight1 ), is( true ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) );
|
||||
// let's make sure these `Hibernate` calls pass for the right reasons...
|
||||
assertThat( flight1.getOrigination(), instanceOf( PersistentAttributeInterceptable.class ) );
|
||||
final PersistentAttributeInterceptable originationProxy = (PersistentAttributeInterceptable) flight1.getOrigination();
|
||||
assertThat( originationProxy.$$_hibernate_getInterceptor(), notNullValue() );
|
||||
assertThat( originationProxy.$$_hibernate_getInterceptor(), instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) );
|
||||
// let's make sure these `Hibernate` calls pass for the right reasons...
|
||||
assertThat( flight1.getDestination(), instanceOf( PersistentAttributeInterceptable.class ) );
|
||||
final PersistentAttributeInterceptable destinationProxy = (PersistentAttributeInterceptable) flight1.getDestination();
|
||||
assertThat( destinationProxy.$$_hibernate_getInterceptor(), notNullValue() );
|
||||
assertThat( destinationProxy.$$_hibernate_getInterceptor(), instanceOf( EnhancementAsProxyLazinessInterceptor.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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.mapping.lazytoone;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class LazyToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Airport.class, Flight.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) {
|
||||
ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Airport austin = new Airport( 1, "AUS" );
|
||||
final Airport baltimore = new Airport( 2, "BWI" );
|
||||
|
||||
final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore );
|
||||
final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin );
|
||||
|
||||
session.persist( austin );
|
||||
session.persist( baltimore );
|
||||
|
||||
session.persist( flight1 );
|
||||
session.persist( flight2 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanupTestData() throws Exception {
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
session.createQuery( "delete Flight" ).executeUpdate();
|
||||
session.createQuery( "delete Airport" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonEnhanced() {
|
||||
final StatisticsImplementor statistics = sessionFactory().getStatistics();
|
||||
statistics.clear();
|
||||
|
||||
inTransaction(
|
||||
(session) -> {
|
||||
final Flight flight1 = session.byId( Flight.class ).load( 1 );
|
||||
|
||||
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
|
||||
|
||||
assertThat( Hibernate.isInitialized( flight1 ), is( true ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) );
|
||||
assertThat( flight1.getOrigination(), instanceOf( HibernateProxy.class ) );
|
||||
|
||||
assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( true ) );
|
||||
assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) );
|
||||
assertThat( flight1.getDestination(), instanceOf( HibernateProxy.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue