HHH-11882 - Bytecode enhancer tests with the new JUnit runner
This commit is contained in:
parent
168a47bdae
commit
fb6a7a376f
|
@ -0,0 +1,207 @@
|
|||
package org.hibernate.test.bytecode.enhancement.access;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
|
||||
@Ignore( "Property access does not allow dirty tracking, so this test fails (on the cleanup method)" )
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-10851" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
@CustomEnhancementContext( {EnhancerTestContext.class, MixedAccessTest.NoDirtyCheckingContext.class} )
|
||||
public class MixedAccessTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private static final ScriptEngine SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName( "javascript" );
|
||||
private static final Function<Map.Entry, String> MAPPING_FUNCTION = e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"";
|
||||
private static boolean cleanup = false;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{TestEntity.class, TestOtherEntity.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity testEntity = new TestEntity( "foo" );
|
||||
testEntity.setParamsAsString( "{\"paramName\":\"paramValue\"}" );
|
||||
s.persist( testEntity );
|
||||
|
||||
TestOtherEntity testOtherEntity = new TestOtherEntity( "foo" );
|
||||
testOtherEntity.setParamsAsString( "{\"paramName\":\"paramValue\"}" );
|
||||
s.persist( testOtherEntity );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity testEntity = s.get( TestEntity.class, "foo" );
|
||||
Assert.assertEquals( "{\"paramName\":\"paramValue\"}", testEntity.getParamsAsString() );
|
||||
|
||||
TestOtherEntity testOtherEntity = s.get( TestOtherEntity.class, "foo" );
|
||||
Assert.assertEquals( "{\"paramName\":\"paramValue\"}", testOtherEntity.getParamsAsString() );
|
||||
|
||||
// Clean parameters
|
||||
cleanup = true;
|
||||
testEntity.setParamsAsString( "{}" );
|
||||
testOtherEntity.setParamsAsString( "{}" );
|
||||
} );
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity testEntity = s.get( TestEntity.class, "foo" );
|
||||
Assert.assertTrue( testEntity.getParams().isEmpty() );
|
||||
|
||||
TestOtherEntity testOtherEntity = s.get( TestOtherEntity.class, "foo" );
|
||||
Assert.assertTrue( testOtherEntity.getParams().isEmpty() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "TEST_ENTITY" )
|
||||
private static class TestEntity {
|
||||
|
||||
@Id
|
||||
String name;
|
||||
|
||||
@Transient
|
||||
Map<String, String> params = new LinkedHashMap<>();
|
||||
|
||||
TestEntity(String name) {
|
||||
this();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
TestEntity() {
|
||||
}
|
||||
|
||||
Map<String, String> getParams() {
|
||||
return Collections.unmodifiableMap( params );
|
||||
}
|
||||
|
||||
void setParams(Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Column( name = "params", length = 4000 )
|
||||
@Access( AccessType.PROPERTY )
|
||||
String getParamsAsString() {
|
||||
return params.isEmpty() ? null : "{" + params.entrySet().stream().map( MAPPING_FUNCTION ).collect( joining( "," ) ) + "}";
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
void setParamsAsString(String string) {
|
||||
params.clear();
|
||||
|
||||
try {
|
||||
if ( string != null ) {
|
||||
params.putAll( (Map<String, String>) SCRIPT_ENGINE.eval( "Java.asJSONCompatible(" + string + ")" ) );
|
||||
}
|
||||
} catch ( ScriptException ignore ) {
|
||||
// JDK 8u60 required --- use hard coded values to pass the test
|
||||
if ( !cleanup ) {
|
||||
params.put( "paramName", "paramValue" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "OTHER_ENTITY" )
|
||||
@Access( AccessType.FIELD )
|
||||
private static class TestOtherEntity {
|
||||
|
||||
@Id
|
||||
String name;
|
||||
|
||||
@Transient
|
||||
Map<String, String> params = new LinkedHashMap<>();
|
||||
|
||||
TestOtherEntity(String name) {
|
||||
this();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
TestOtherEntity() {
|
||||
}
|
||||
|
||||
Map<String, String> getParams() {
|
||||
return Collections.unmodifiableMap( params );
|
||||
}
|
||||
|
||||
void setParams(Map<String, String> params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Column( name = "params", length = 4000 )
|
||||
@Access( AccessType.PROPERTY )
|
||||
String getParamsAsString() {
|
||||
return params.isEmpty() ? null : "{" + params.entrySet().stream().map( MAPPING_FUNCTION ).collect( joining( "," ) ) + "}";
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
void setParamsAsString(String string) {
|
||||
params.clear();
|
||||
|
||||
try {
|
||||
if ( string != null ) {
|
||||
params.putAll( (Map<String, String>) SCRIPT_ENGINE.eval( "Java.asJSONCompatible(" + string + ")" ) );
|
||||
}
|
||||
} catch ( ScriptException ignore ) {
|
||||
// JDK 8u60 required --- use hard coded values to pass the test
|
||||
if ( !cleanup ) {
|
||||
params.put( "paramName", "paramValue" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
public static class NoDirtyCheckingContext extends DefaultEnhancementContext {
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.association;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11050" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class InheritedAttributeAssociationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// The mapping is wrong but the point is that the enhancement phase does not need to fail. See JIRA for further detail
|
||||
|
||||
// If enhancement of 'items' attribute fails, 'name' won't be enhanced
|
||||
Author author = new Author();
|
||||
author.name = "Bernardo Soares";
|
||||
EnhancerTestUtils.checkDirtyTracking( author, "name" );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
private static class Author {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@OneToMany( fetch = FetchType.LAZY, mappedBy = "author" )
|
||||
List<ChildItem> items;
|
||||
|
||||
// keep this field after 'items'
|
||||
String name;
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
|
||||
@DiscriminatorColumn( name = "type", discriminatorType = DiscriminatorType.STRING )
|
||||
private static abstract class Item {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToOne( fetch = FetchType.LAZY )
|
||||
Author author;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@DiscriminatorValue( "child" )
|
||||
private static class ChildItem extends Item {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.association;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class ManyToManyAssociationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Group group = new Group();
|
||||
Group anotherGroup = new Group();
|
||||
|
||||
User user = new User();
|
||||
User anotherUser = new User();
|
||||
|
||||
user.addGroup( group );
|
||||
user.addGroup( anotherGroup );
|
||||
anotherUser.addGroup( group );
|
||||
|
||||
Assert.assertEquals( 2, group.getUsers().size() );
|
||||
Assert.assertEquals( 1, anotherGroup.getUsers().size() );
|
||||
|
||||
group.resetUsers();
|
||||
|
||||
Assert.assertEquals( 1, user.getGroups().size() );
|
||||
Assert.assertEquals( 0, anotherUser.getGroups().size() );
|
||||
|
||||
// Test remove
|
||||
user.addGroup( group );
|
||||
anotherUser.addGroup( group );
|
||||
|
||||
Assert.assertEquals( 2, group.getUsers().size() );
|
||||
Assert.assertEquals( 1, anotherGroup.getUsers().size() );
|
||||
|
||||
Set<Group> groups = new HashSet<>( user.getGroups() );
|
||||
groups.remove( group );
|
||||
user.setGroups( groups );
|
||||
|
||||
Assert.assertEquals( 1, group.getUsers().size() );
|
||||
Assert.assertEquals( 1, anotherGroup.getUsers().size() );
|
||||
|
||||
groups.remove( anotherGroup );
|
||||
user.setGroups( groups );
|
||||
|
||||
Assert.assertEquals( 1, group.getUsers().size() );
|
||||
// This happens (and is expected) because there was no snapshot taken before remove
|
||||
Assert.assertEquals( 1, anotherGroup.getUsers().size() );
|
||||
}
|
||||
|
||||
// -- //
|
||||
|
||||
@Entity
|
||||
private static class Group {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Column
|
||||
String name;
|
||||
|
||||
@ManyToMany( mappedBy = "groups" )
|
||||
Set<User> users = new HashSet<>();
|
||||
|
||||
Set<User> getUsers() {
|
||||
return Collections.unmodifiableSet( users );
|
||||
}
|
||||
|
||||
void resetUsers() {
|
||||
// this wouldn't trigger association management: users.clear();
|
||||
users = new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class User {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String password;
|
||||
|
||||
@ManyToMany
|
||||
Set<Group> groups;
|
||||
|
||||
void addGroup(Group group) {
|
||||
Set<Group> groups = this.groups == null ? new HashSet<>() : this.groups;
|
||||
groups.add( group );
|
||||
this.groups = groups;
|
||||
}
|
||||
|
||||
Set<Group> getGroups() {
|
||||
return Collections.unmodifiableSet( groups );
|
||||
}
|
||||
|
||||
void setGroups(Set<Group> groups) {
|
||||
this.groups = groups;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.association;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class OneToManyAssociationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Customer customer = new Customer();
|
||||
Assert.assertTrue( customer.getInventories().isEmpty() );
|
||||
|
||||
CustomerInventory customerInventory = new CustomerInventory();
|
||||
customerInventory.setCustomer( customer );
|
||||
|
||||
Assert.assertEquals( 1, customer.getInventories().size() );
|
||||
Assert.assertTrue( customer.getInventories().contains( customerInventory ) );
|
||||
|
||||
Customer anotherCustomer = new Customer();
|
||||
Assert.assertTrue( anotherCustomer.getInventories().isEmpty() );
|
||||
customerInventory.setCustomer( anotherCustomer );
|
||||
|
||||
Assert.assertTrue( customer.getInventories().isEmpty() );
|
||||
Assert.assertEquals( 1, anotherCustomer.getInventories().size() );
|
||||
Assert.assertSame( customerInventory, anotherCustomer.getInventories().get( 0 ) );
|
||||
|
||||
customer.addInventory( customerInventory );
|
||||
|
||||
Assert.assertSame( customer, customerInventory.getCustomer() );
|
||||
Assert.assertTrue( anotherCustomer.getInventories().isEmpty() );
|
||||
Assert.assertEquals( 1, customer.getInventories().size() );
|
||||
|
||||
customer.addInventory( new CustomerInventory() );
|
||||
Assert.assertEquals( 2, customer.getInventories().size() );
|
||||
|
||||
// Test remove
|
||||
customer.removeInventory( customerInventory );
|
||||
Assert.assertEquals( 1, customer.getInventories().size() );
|
||||
|
||||
// This happens (and is expected) because there was no snapshot taken before remove
|
||||
Assert.assertNotNull( customerInventory.getCustomer() );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
private static class Customer {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToMany( mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER )
|
||||
List<CustomerInventory> customerInventories = new ArrayList<>();
|
||||
|
||||
void addInventory(CustomerInventory inventory) {
|
||||
List<CustomerInventory> list = customerInventories;
|
||||
list.add( inventory );
|
||||
customerInventories = list;
|
||||
}
|
||||
|
||||
List<CustomerInventory> getInventories() {
|
||||
return Collections.unmodifiableList( customerInventories );
|
||||
}
|
||||
|
||||
void removeInventory(CustomerInventory inventory) {
|
||||
customerInventories.remove( inventory );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class CustomerInventory {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Id
|
||||
Long custId;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.MERGE )
|
||||
Customer customer;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.MERGE )
|
||||
String vehicle;
|
||||
|
||||
Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
void setVehicle(String vehicle) {
|
||||
this.vehicle = vehicle;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.association;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class OneToOneAssociationTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
User user = new User();
|
||||
user.setLogin( UUID.randomUUID().toString() );
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.setUser( user );
|
||||
|
||||
Assert.assertEquals( customer, user.getCustomer() );
|
||||
|
||||
// check dirty tracking is set automatically with bi-directional association management
|
||||
EnhancerTestUtils.checkDirtyTracking( user, "login", "customer" );
|
||||
|
||||
User anotherUser = new User();
|
||||
anotherUser.setLogin( UUID.randomUUID().toString() );
|
||||
|
||||
customer.setUser( anotherUser );
|
||||
|
||||
Assert.assertNull( user.getCustomer() );
|
||||
Assert.assertEquals( customer, anotherUser.getCustomer() );
|
||||
|
||||
user.setCustomer( new Customer() );
|
||||
|
||||
Assert.assertEquals( user, user.getCustomer().getUser() );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
private static class Customer {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@OneToOne
|
||||
User user;
|
||||
|
||||
User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
void setUser(User newUser) {
|
||||
user = newUser;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class User {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String login;
|
||||
|
||||
String password;
|
||||
|
||||
@OneToOne( mappedBy = "user" )
|
||||
Customer customer;
|
||||
|
||||
void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.basic;
|
||||
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class BasicEnhancementTest {
|
||||
|
||||
@Test
|
||||
public void basicManagedTest() {
|
||||
SimpleEntity entity = new SimpleEntity();
|
||||
|
||||
// Call the new ManagedEntity methods
|
||||
assertTyping( ManagedEntity.class, entity );
|
||||
ManagedEntity managedEntity = (ManagedEntity) entity;
|
||||
assertSame( entity, managedEntity.$$_hibernate_getEntityInstance() );
|
||||
|
||||
assertNull( managedEntity.$$_hibernate_getEntityEntry() );
|
||||
managedEntity.$$_hibernate_setEntityEntry( EnhancerTestUtils.makeEntityEntry() );
|
||||
assertNotNull( managedEntity.$$_hibernate_getEntityEntry() );
|
||||
managedEntity.$$_hibernate_setEntityEntry( null );
|
||||
assertNull( managedEntity.$$_hibernate_getEntityEntry() );
|
||||
|
||||
managedEntity.$$_hibernate_setNextManagedEntity( managedEntity );
|
||||
managedEntity.$$_hibernate_setPreviousManagedEntity( managedEntity );
|
||||
assertSame( managedEntity, managedEntity.$$_hibernate_getNextManagedEntity() );
|
||||
assertSame( managedEntity, managedEntity.$$_hibernate_getPreviousManagedEntity() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicInterceptableTest() {
|
||||
SimpleEntity entity = new SimpleEntity();
|
||||
|
||||
assertTyping( PersistentAttributeInterceptable.class, entity );
|
||||
PersistentAttributeInterceptable interceptableEntity = (PersistentAttributeInterceptable) entity;
|
||||
|
||||
assertNull( interceptableEntity.$$_hibernate_getInterceptor() );
|
||||
interceptableEntity.$$_hibernate_setInterceptor( new ObjectAttributeMarkerInterceptor() );
|
||||
assertNotNull( interceptableEntity.$$_hibernate_getInterceptor() );
|
||||
|
||||
assertNull( EnhancerTestUtils.getFieldByReflection( entity, "anUnspecifiedObject" ) );
|
||||
entity.setAnObject( new Object() );
|
||||
|
||||
assertSame( ObjectAttributeMarkerInterceptor.WRITE_MARKER, EnhancerTestUtils.getFieldByReflection( entity, "anUnspecifiedObject" ) );
|
||||
assertSame( ObjectAttributeMarkerInterceptor.READ_MARKER, entity.getAnObject() );
|
||||
|
||||
entity.setAnObject( null );
|
||||
assertSame( ObjectAttributeMarkerInterceptor.WRITE_MARKER, EnhancerTestUtils.getFieldByReflection( entity, "anUnspecifiedObject" ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicExtendedEnhancementTest() {
|
||||
// test uses ObjectAttributeMarkerInterceptor to ensure that field access is routed through enhanced methods
|
||||
|
||||
SimpleEntity entity = new SimpleEntity();
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( new ObjectAttributeMarkerInterceptor() );
|
||||
|
||||
Object decoy = new Object();
|
||||
entity.anUnspecifiedObject = decoy;
|
||||
|
||||
Object gotByReflection = EnhancerTestUtils.getFieldByReflection( entity, "anUnspecifiedObject" );
|
||||
assertNotSame( decoy, gotByReflection );
|
||||
assertSame( ObjectAttributeMarkerInterceptor.WRITE_MARKER, gotByReflection );
|
||||
|
||||
Object entityObject = entity.anUnspecifiedObject;
|
||||
|
||||
assertNotSame( decoy, entityObject );
|
||||
assertSame( ObjectAttributeMarkerInterceptor.READ_MARKER, entityObject );
|
||||
|
||||
// do some more calls on the various types, without the interceptor
|
||||
( (PersistentAttributeInterceptable) entity ).$$_hibernate_setInterceptor( null );
|
||||
|
||||
entity.id = 1234567890L;
|
||||
Assert.assertEquals( 1234567890L, (long) entity.getId() );
|
||||
|
||||
entity.name = "Entity Name";
|
||||
assertSame( "Entity Name", entity.name );
|
||||
|
||||
entity.active = true;
|
||||
assertTrue( entity.getActive() );
|
||||
|
||||
entity.someStrings = Arrays.asList( "A", "B", "C", "D" );
|
||||
assertArrayEquals( new String[]{"A", "B", "C", "D"}, entity.someStrings.toArray() );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
public static class ObjectAttributeMarkerInterceptor implements PersistentAttributeInterceptor {
|
||||
|
||||
public static final Object READ_MARKER = new Object();
|
||||
public static final Object WRITE_MARKER = new Object();
|
||||
|
||||
@Override
|
||||
public boolean readBoolean(Object obj, String name, boolean oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte readByte(Object obj, String name, byte oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte writeByte(Object obj, String name, byte oldValue, byte newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar(Object obj, String name, char oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char writeChar(Object obj, String name, char oldValue, char newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShort(Object obj, String name, short oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short writeShort(Object obj, String name, short oldValue, short newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt(Object obj, String name, int oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeInt(Object obj, String name, int oldValue, int newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float readFloat(Object obj, String name, float oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float writeFloat(Object obj, String name, float oldValue, float newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readDouble(Object obj, String name, double oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double writeDouble(Object obj, String name, double oldValue, double newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong(Object obj, String name, long oldValue) {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long writeLong(Object obj, String name, long oldValue, long newValue) {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readObject(Object obj, String name, Object oldValue) {
|
||||
return READ_MARKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object writeObject(Object obj, String name, Object oldValue, Object newValue) {
|
||||
return WRITE_MARKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getInitializedLazyAttributeNames() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeInitialized(String name) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
private static class SimpleEntity {
|
||||
|
||||
Object anUnspecifiedObject;
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Boolean active;
|
||||
|
||||
List<String> someStrings;
|
||||
|
||||
Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Boolean getActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(Boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
Object getAnObject() {
|
||||
return anUnspecifiedObject;
|
||||
}
|
||||
|
||||
void setAnObject(Object providedObject) {
|
||||
this.anUnspecifiedObject = providedObject;
|
||||
}
|
||||
|
||||
List<String> getSomeStrings() {
|
||||
return Collections.unmodifiableList( someStrings );
|
||||
}
|
||||
|
||||
void setSomeStrings(List<String> someStrings) {
|
||||
this.someStrings = someStrings;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.basic;
|
||||
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class BasicSessionTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
buildSessionFactory( configuration -> configuration.addAnnotatedClass( MyEntity.class ) );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.save( new MyEntity( 1L ) );
|
||||
s.save( new MyEntity( 2L ) );
|
||||
} );
|
||||
|
||||
MyEntity[] entities = new MyEntity[2];
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entities[0] = s.get( MyEntity.class, 1L );
|
||||
entities[1] = s.get( MyEntity.class, 2L );
|
||||
|
||||
assertNotNull( entities[0].$$_hibernate_getEntityInstance() );
|
||||
assertSame( entities[0], entities[0].$$_hibernate_getEntityInstance() );
|
||||
assertNotNull( entities[0].$$_hibernate_getEntityEntry() );
|
||||
assertNull( entities[0].$$_hibernate_getPreviousManagedEntity() );
|
||||
assertNotNull( entities[0].$$_hibernate_getNextManagedEntity() );
|
||||
|
||||
assertNotNull( entities[1].$$_hibernate_getEntityInstance() );
|
||||
assertSame( entities[1], entities[1].$$_hibernate_getEntityInstance() );
|
||||
assertNotNull( entities[1].$$_hibernate_getEntityEntry() );
|
||||
assertNotNull( entities[1].$$_hibernate_getPreviousManagedEntity() );
|
||||
assertNull( entities[1].$$_hibernate_getNextManagedEntity() );
|
||||
|
||||
s.createQuery( "delete MyEntity" ).executeUpdate();
|
||||
} );
|
||||
|
||||
assertNull( entities[0].$$_hibernate_getEntityEntry() );
|
||||
assertNull( entities[1].$$_hibernate_getEntityEntry() );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "MyEntity" )
|
||||
@Table( name = "MY_ENTITY" )
|
||||
private static class MyEntity implements ManagedEntity {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Transient
|
||||
private transient EntityEntry entityEntry;
|
||||
@Transient
|
||||
private transient ManagedEntity previous;
|
||||
@Transient
|
||||
private transient ManagedEntity next;
|
||||
|
||||
MyEntity() {
|
||||
}
|
||||
|
||||
MyEntity(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object $$_hibernate_getEntityInstance() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityEntry $$_hibernate_getEntityEntry() {
|
||||
return entityEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void $$_hibernate_setEntityEntry(EntityEntry entityEntry) {
|
||||
this.entityEntry = entityEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedEntity $$_hibernate_getNextManagedEntity() {
|
||||
return next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void $$_hibernate_setNextManagedEntity(ManagedEntity next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedEntity $$_hibernate_getPreviousManagedEntity() {
|
||||
return previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void $$_hibernate_setPreviousManagedEntity(ManagedEntity previous) {
|
||||
this.previous = previous;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.basic;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MapsId;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-9529" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class CrossEnhancementTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class, Child.class, ChildKey.class};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
buildSessionFactory();
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
@Id
|
||||
String id;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
private static class ChildKey implements Serializable {
|
||||
String parent;
|
||||
String type;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
@EmbeddedId
|
||||
ChildKey id;
|
||||
|
||||
@MapsId( "parent" )
|
||||
@ManyToOne
|
||||
Parent parent;
|
||||
|
||||
public String getfieldOnChildKeyParent() {
|
||||
// Note that there are two GETFIELD ops here, one on the field 'id' that should be enhanced and another
|
||||
// on the field 'parent' that may be or not (depending if 'extended enhancement' is enabled)
|
||||
|
||||
// Either way, the field 'parent' on ChildKey should not be confused with the field 'parent' on Child
|
||||
|
||||
return id.parent;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.basic;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class ExtendedAssociationManagementTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
User user = new User();
|
||||
user.login = UUID.randomUUID().toString();
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.user = user;
|
||||
|
||||
assertEquals( customer, getFieldByReflection( user, "customer" ) );
|
||||
|
||||
// check dirty tracking is set automatically with bi-directional association management
|
||||
EnhancerTestUtils.checkDirtyTracking( user, "login", "customer" );
|
||||
|
||||
User anotherUser = new User();
|
||||
anotherUser.login = UUID.randomUUID().toString();
|
||||
|
||||
customer.user = anotherUser;
|
||||
|
||||
Assert.assertNull( user.customer );
|
||||
assertEquals( customer, getFieldByReflection( anotherUser, "customer" ) );
|
||||
|
||||
user.customer = new Customer();
|
||||
assertEquals( user, user.customer.user );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
private static class Customer {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String firstName;
|
||||
|
||||
String lastName;
|
||||
|
||||
@OneToOne( fetch = FetchType.LAZY )
|
||||
User user;
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class User {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String login;
|
||||
|
||||
String password;
|
||||
|
||||
@OneToOne( mappedBy = "user", fetch = FetchType.LAZY )
|
||||
Customer customer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package org.hibernate.test.bytecode.enhancement.basic;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.clearDirtyTracking;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
* @author Craig Andrews
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11284" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
@CustomEnhancementContext( {EnhancerTestContext.class, InheritedTest.EagerEnhancementContext.class} )
|
||||
public class InheritedTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Employee charles = new Employee( "Charles", "Engineer" );
|
||||
charles.setOca( 1002 );
|
||||
|
||||
// Check that both types of class attributes are being dirty tracked
|
||||
checkDirtyTracking( charles, "title", "oca" );
|
||||
clearDirtyTracking( charles );
|
||||
|
||||
// Let's give charles a promotion, this time using method references
|
||||
charles.setOca( 99 );
|
||||
charles.setTitle( "Manager" );
|
||||
|
||||
checkDirtyTracking( charles, "title", "oca" );
|
||||
|
||||
Contractor bob = new Contractor( "Bob", 100 );
|
||||
bob.setOca( 1003 );
|
||||
|
||||
// Check that both types of class attributes are being dirty tracked
|
||||
checkDirtyTracking( bob, "rate", "oca" );
|
||||
clearDirtyTracking( bob );
|
||||
|
||||
// Let's give bob a rate increase, this time using method references
|
||||
bob.setOca( 88 );
|
||||
bob.setRate( 200 );
|
||||
|
||||
checkDirtyTracking( bob, "rate", "oca" );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
private static abstract class Person {
|
||||
|
||||
@Id
|
||||
String name;
|
||||
|
||||
@Version
|
||||
long oca;
|
||||
|
||||
Person() {
|
||||
}
|
||||
|
||||
Person(String name) {
|
||||
this();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
void setOca(long l) {
|
||||
this.oca = l;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class Employee extends Person {
|
||||
|
||||
String title;
|
||||
|
||||
Employee() {
|
||||
}
|
||||
|
||||
Employee(String name, String title) {
|
||||
super( name );
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class Contractor extends Person {
|
||||
|
||||
Integer rate;
|
||||
|
||||
Contractor() {
|
||||
}
|
||||
|
||||
Contractor(String name, Integer rate) {
|
||||
super( name );
|
||||
this.rate = rate;
|
||||
}
|
||||
|
||||
void setRate(Integer rate) {
|
||||
this.rate = rate;
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
public static class EagerEnhancementContext extends DefaultEnhancementContext {
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
// HHH-10981 - Without lazy loading, the generation of getters and setters has a different code path
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package org.hibernate.test.bytecode.enhancement.basic;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.clearDirtyTracking;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-10646" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
@CustomEnhancementContext( {EnhancerTestContext.class, MappedSuperclassTest.EagerEnhancementContext.class} )
|
||||
public class MappedSuperclassTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Employee charles = new Employee( "Charles", "Engineer" );
|
||||
charles.setOca( 1002 );
|
||||
|
||||
// Check that both types of class attributes are being dirty tracked
|
||||
checkDirtyTracking( charles, "title", "oca" );
|
||||
clearDirtyTracking( charles );
|
||||
|
||||
// Let's give charles a promotion, this time using method references
|
||||
charles.setOca( 99 );
|
||||
charles.setTitle( "Manager" );
|
||||
|
||||
checkDirtyTracking( charles, "title", "oca" );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@MappedSuperclass
|
||||
private static class Person {
|
||||
|
||||
@Id
|
||||
String name;
|
||||
|
||||
@Version
|
||||
Long oca;
|
||||
|
||||
Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Person() {
|
||||
}
|
||||
|
||||
void setOca(long l) {
|
||||
this.oca = l;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class Employee extends Person {
|
||||
|
||||
String title;
|
||||
|
||||
Employee(String name, String title) {
|
||||
super( name );
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
Employee() {
|
||||
}
|
||||
|
||||
void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
public static class EagerEnhancementContext extends DefaultEnhancementContext {
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
// HHH-10981 - Without lazy loading, the generation of getters and setters has a different code path
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.cascade;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-10252" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class CascadeDeleteTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{Parent.class, Child.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
// Create a Parent with one Child
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent p = new Parent();
|
||||
p.setName( "PARENT" );
|
||||
p.setLazy( "LAZY" );
|
||||
p.makeChild();
|
||||
s.persist( p );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// Delete the Parent
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent loadedParent = (Parent) s.createQuery( "SELECT p FROM Parent p WHERE name=:name" )
|
||||
.setParameter( "name", "PARENT" )
|
||||
.uniqueResult();
|
||||
|
||||
s.delete( loadedParent );
|
||||
} );
|
||||
// If the lazy relation is not fetch on cascade there is a constraint violation on commit
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Parent" )
|
||||
@Table( name = "PARENT" )
|
||||
public static class Parent {
|
||||
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
List<Child> children = new ArrayList<>();
|
||||
|
||||
String lazy;
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany( mappedBy = "parent", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, fetch = FetchType.LAZY )
|
||||
List<Child> getChildren() {
|
||||
return Collections.unmodifiableList( children );
|
||||
}
|
||||
|
||||
void setChildren(List<Child> children) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String getLazy() {
|
||||
return lazy;
|
||||
}
|
||||
|
||||
void setLazy(String lazy) {
|
||||
this.lazy = lazy;
|
||||
}
|
||||
|
||||
void makeChild() {
|
||||
Child c = new Child();
|
||||
c.setParent( this );
|
||||
children.add( c );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@ManyToOne( optional = false )
|
||||
@JoinColumn( name = "parent_id" )
|
||||
Parent parent;
|
||||
|
||||
Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Parent getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
void setParent(Parent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.cascade;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-10252" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class CascadeWithFkConstraintTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private String garageId, car1Id, car2Id;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Garage.class, Car.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
// Create garage, add 2 cars to garage
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
|
||||
Garage garage = new Garage();
|
||||
Car car1 = new Car();
|
||||
Car car2 = new Car();
|
||||
garage.insert( car1 );
|
||||
garage.insert( car2 );
|
||||
|
||||
em.persist( garage );
|
||||
em.persist( car1 );
|
||||
em.persist( car2 );
|
||||
|
||||
garageId = garage.id;
|
||||
car1Id = car1.id;
|
||||
car2Id = car2.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
// Remove garage
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
Garage toRemoveGarage = em.find( Garage.class, garageId );
|
||||
em.remove( toRemoveGarage );
|
||||
} );
|
||||
|
||||
// Check if there is no garage but cars are still present
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
Garage foundGarage = em.find( Garage.class, garageId );
|
||||
Assert.assertNull( foundGarage );
|
||||
|
||||
Car foundCar1 = em.find( Car.class, car1Id );
|
||||
Assert.assertEquals( car1Id, foundCar1.id );
|
||||
|
||||
Car foundCar2 = em.find( Car.class, car2Id );
|
||||
Assert.assertEquals( car2Id, foundCar2.id );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "GARAGE" )
|
||||
private static class Garage {
|
||||
|
||||
@Id
|
||||
String id;
|
||||
|
||||
@OneToMany
|
||||
@JoinColumn( name = "GARAGE_ID" )
|
||||
Set<Car> cars = new HashSet<>();
|
||||
|
||||
Garage() {
|
||||
id = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
void insert(Car aCar) {
|
||||
cars.add( aCar );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CAR" )
|
||||
public static class Car {
|
||||
|
||||
@Id
|
||||
String id;
|
||||
|
||||
Car() {
|
||||
id = UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.hibernate.test.bytecode.enhancement.detached;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11426" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class DetachedGetIdentifierTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{SimpleEntity.class};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
buildSessionFactory();
|
||||
|
||||
SimpleEntity[] entities = new SimpleEntity[2];
|
||||
entities[0] = new SimpleEntity();
|
||||
entities[0].name = "test";
|
||||
|
||||
TransactionUtil.doInJPA( this::sessionFactory, em -> {
|
||||
entities[1] = em.merge( entities[0] );
|
||||
assertNotNull( em.getEntityManagerFactory().getPersistenceUnitUtil().getIdentifier( entities[1] ) );
|
||||
} );
|
||||
|
||||
// Call as detached entity
|
||||
try ( SessionFactory sessionFactory = sessionFactory() ) {
|
||||
assertNotNull( sessionFactory.getPersistenceUnitUtil().getIdentifier( entities[1] ) );
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "SIMPLE_ENTITY" )
|
||||
private static class SimpleEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.dirty;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11293" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class DirtyTrackingCollectionTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{StringsEntity.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
StringsEntity entity = new StringsEntity();
|
||||
entity.id = 1L;
|
||||
entity.someStrings = new ArrayList<>( Arrays.asList( "a", "b", "c" ) );
|
||||
em.persist( entity );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::sessionFactory, entityManager -> {
|
||||
StringsEntity entity = entityManager.find( StringsEntity.class, 1L );
|
||||
entity.someStrings.clear();
|
||||
} );
|
||||
|
||||
doInJPA( this::sessionFactory, entityManager -> {
|
||||
StringsEntity entity = entityManager.find( StringsEntity.class, 1L );
|
||||
assertEquals( 0, entity.someStrings.size() );
|
||||
entity.someStrings.add( "d" );
|
||||
} );
|
||||
|
||||
doInJPA( this::sessionFactory, entityManager -> {
|
||||
StringsEntity entity = entityManager.find( StringsEntity.class, 1L );
|
||||
assertEquals( 1, entity.someStrings.size() );
|
||||
entity.someStrings = new ArrayList<>();
|
||||
} );
|
||||
|
||||
doInJPA( this::sessionFactory, entityManager -> {
|
||||
StringsEntity entity = entityManager.find( StringsEntity.class, 1L );
|
||||
assertEquals( 0, entity.someStrings.size() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "STRINGS_ENTITY" )
|
||||
private static class StringsEntity {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@ElementCollection
|
||||
List<String> someStrings;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.dirty;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class DirtyTrackingTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
SimpleEntity entity = new SimpleEntity();
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
// Basic single field
|
||||
Long number = entity.getSomeNumber();
|
||||
EnhancerTestUtils.checkDirtyTracking( entity );
|
||||
entity.setSomeNumber( number + 1L );
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "someNumber" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
entity.setSomeNumber( entity.getSomeNumber() );
|
||||
EnhancerTestUtils.checkDirtyTracking( entity );
|
||||
|
||||
// Basic multi-field (Id properties are not flagged as dirty)
|
||||
entity.id = 2L;
|
||||
entity.active = !entity.active;
|
||||
entity.someNumber = 193L;
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "active", "someNumber" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
// Setting the same value should not make it dirty
|
||||
entity.someNumber = 193L;
|
||||
EnhancerTestUtils.checkDirtyTracking( entity );
|
||||
|
||||
// Collection
|
||||
List<String> stringList = new ArrayList<>();
|
||||
stringList.add( "FooBar" );
|
||||
entity.someStrings = stringList;
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "someStrings" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
stringList.add( "BarFoo" );
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "someStrings" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
// Association: this should not set the entity to dirty
|
||||
Set<Integer> intSet = new HashSet<>();
|
||||
intSet.add( 42 );
|
||||
entity.someInts = intSet;
|
||||
EnhancerTestUtils.checkDirtyTracking( entity );
|
||||
|
||||
// testing composite object
|
||||
Address address = new Address();
|
||||
entity.address = address;
|
||||
address.city = "Arendal";
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "address" );
|
||||
EnhancerTestUtils.clearDirtyTracking( entity );
|
||||
|
||||
// make sure that new composite instances are cleared
|
||||
Address address2 = new Address();
|
||||
entity.address = address2;
|
||||
address.street1 = "Heggedalveien";
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "address" );
|
||||
|
||||
Country country = new Country();
|
||||
address2.country = country;
|
||||
country.name = "Norway";
|
||||
EnhancerTestUtils.checkDirtyTracking( entity, "address", "address.country" );
|
||||
|
||||
address.country = null;
|
||||
entity.address = null;
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Embeddable
|
||||
private static class Address {
|
||||
@Embedded
|
||||
Country country;
|
||||
String street1;
|
||||
String street2;
|
||||
String city;
|
||||
String state;
|
||||
String zip;
|
||||
String phone;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
private static class Country {
|
||||
String name;
|
||||
}
|
||||
|
||||
@Entity
|
||||
private static class SimpleEntity {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Boolean active = Boolean.FALSE;
|
||||
|
||||
Long someNumber = 0L;
|
||||
|
||||
List<String> someStrings;
|
||||
|
||||
@OneToMany
|
||||
Set<Integer> someInts;
|
||||
|
||||
@Embedded
|
||||
Address address;
|
||||
|
||||
@Embedded
|
||||
Address address2;
|
||||
|
||||
public Long getSomeNumber() {
|
||||
return someNumber;
|
||||
}
|
||||
|
||||
public void setSomeNumber(Long someNumber) {
|
||||
this.someNumber = someNumber;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.test.bytecode.enhancement.eviction;
|
||||
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class EvictionTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
// Create a Parent
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent p = new Parent();
|
||||
p.name = "PARENT";
|
||||
s.persist( p );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
|
||||
// Delete the Parent
|
||||
Parent loadedParent = (Parent) s.createQuery( "SELECT p FROM Parent p WHERE name=:name" )
|
||||
.setParameter( "name", "PARENT" )
|
||||
.uniqueResult();
|
||||
assertTyping( ManagedEntity.class, loadedParent );
|
||||
ManagedEntity managedParent = (ManagedEntity) loadedParent;
|
||||
|
||||
// before eviction
|
||||
assertNotNull( managedParent.$$_hibernate_getEntityInstance() );
|
||||
assertNotNull( managedParent.$$_hibernate_getEntityEntry() );
|
||||
assertNull( managedParent.$$_hibernate_getPreviousManagedEntity() );
|
||||
assertNull( managedParent.$$_hibernate_getNextManagedEntity() );
|
||||
|
||||
assertTrue( s.contains( managedParent ) );
|
||||
s.evict( managedParent );
|
||||
|
||||
// after eviction
|
||||
assertFalse( s.contains( managedParent ) );
|
||||
assertNotNull( managedParent.$$_hibernate_getEntityInstance() );
|
||||
assertNull( managedParent.$$_hibernate_getEntityEntry() );
|
||||
assertNull( managedParent.$$_hibernate_getPreviousManagedEntity() );
|
||||
assertNull( managedParent.$$_hibernate_getNextManagedEntity() );
|
||||
|
||||
// evict again
|
||||
s.evict( managedParent );
|
||||
|
||||
assertFalse( s.contains( managedParent ) );
|
||||
assertNotNull( managedParent.$$_hibernate_getEntityInstance() );
|
||||
assertNull( managedParent.$$_hibernate_getEntityEntry() );
|
||||
assertNull( managedParent.$$_hibernate_getPreviousManagedEntity() );
|
||||
assertNull( managedParent.$$_hibernate_getNextManagedEntity() );
|
||||
|
||||
s.delete( managedParent );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Parent" )
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
}
|
||||
}
|
|
@ -6,64 +6,61 @@
|
|||
*/
|
||||
package org.hibernate.test.bytecode.enhancement.javassist;
|
||||
|
||||
import javassist.CtClass;
|
||||
import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl;
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import javassist.CtClass;
|
||||
|
||||
import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class EnhancerFileNotFoundTest extends BaseUnitTestCase {
|
||||
public class EnhancerFileNotFoundTest {
|
||||
|
||||
public static class Enhancer extends EnhancerImpl {
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-11307" )
|
||||
public void test() throws Exception {
|
||||
Enhancer enhancer = new Enhancer( new DefaultEnhancementContext() );
|
||||
try {
|
||||
Class<?> clazz = getClass().getClassLoader().loadClass( Hidden.class.getName() );
|
||||
String resourceName = clazz.getName().replace( '.', '/' ) + ".class";
|
||||
URL url = getClass().getClassLoader().getResource( resourceName );
|
||||
if ( url != null ) {
|
||||
Files.delete( Paths.get( url.toURI() ) );
|
||||
enhancer.loadCtClassFromClass( clazz );
|
||||
}
|
||||
fail( "Should throw FileNotFoundException!" );
|
||||
} catch ( Exception expected ) {
|
||||
assertSame( FileNotFoundException.class, expected.getCause().getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public Enhancer(EnhancementContext enhancementContext) {
|
||||
super( enhancementContext );
|
||||
}
|
||||
// --- //
|
||||
|
||||
@Override
|
||||
public CtClass loadCtClassFromClass(Class<?> aClass) {
|
||||
return super.loadCtClassFromClass( aClass );
|
||||
}
|
||||
}
|
||||
private static class Enhancer extends EnhancerImpl {
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-11307")
|
||||
public void test()
|
||||
throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
EnhancementContext enhancementContextMock = mock( EnhancementContext.class );
|
||||
public Enhancer(EnhancementContext enhancementContext) {
|
||||
super( enhancementContext );
|
||||
}
|
||||
|
||||
Enhancer enhancer = new Enhancer( enhancementContextMock );
|
||||
try {
|
||||
Class<?> clazz = Hidden.class;
|
||||
String resourceName = Hidden.class.getName().replace( '.', '/' ) + ".class";
|
||||
URL url = getClass().getClassLoader().getResource( resourceName );
|
||||
Files.delete( Paths.get(url.toURI()) );
|
||||
enhancer.loadCtClassFromClass( clazz );
|
||||
fail("Should throw FileNotFoundException!");
|
||||
}
|
||||
catch ( Exception expected ) {
|
||||
assertEquals( FileNotFoundException.class, expected.getCause().getClass() );
|
||||
}
|
||||
}
|
||||
@Override
|
||||
// change visibility protected -> public
|
||||
public CtClass loadCtClassFromClass(Class<?> aClass) {
|
||||
return super.loadCtClassFromClass( aClass );
|
||||
}
|
||||
}
|
||||
|
||||
private static class Hidden {
|
||||
|
||||
}
|
||||
// --- //
|
||||
|
||||
private static class Hidden {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
package org.hibernate.test.bytecode.enhancement.join;
|
||||
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.Hibernate.isInitialized;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-3949" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class HHH3949Test extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Person.class, Vehicle.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
// see HHH-3949 for further details ^^^^^
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
|
||||
// it is important that the data associations remain as follows:
|
||||
// * Johnny <-> Volkswagen Golf
|
||||
// * Ricky <-> Subaru Impreza
|
||||
// * Rosy -> none
|
||||
// * none <- Renault Truck
|
||||
//
|
||||
// see #shouldHaveVehicle and #shouldHaveDriver
|
||||
|
||||
Person person1 = new Person( "Johnny" );
|
||||
Person person2 = new Person( "Ricky" );
|
||||
Person person3 = new Person( "Rosy" );
|
||||
s.save( person1 );
|
||||
s.save( person2 );
|
||||
s.save( person3 );
|
||||
|
||||
Vehicle vehicle1 = new Vehicle( "Volkswagen Golf" );
|
||||
vehicle1.setDriver( person1 );
|
||||
s.save( vehicle1 );
|
||||
|
||||
Vehicle vehicle2 = new Vehicle( "Subaru Impreza" );
|
||||
vehicle2.setDriver( person2 );
|
||||
person2.setVehicle( vehicle2 );
|
||||
s.save( vehicle2 );
|
||||
|
||||
Vehicle vehicle3 = new Vehicle( "Renault Truck" );
|
||||
s.save( vehicle3 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
// verify the work around query
|
||||
performQueryAndVerifyPersonResults( "from Person p fetch all properties left join fetch p.vehicle" );
|
||||
performQueryAndVerifyPersonResults( "from Person p left join fetch p.vehicle" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
performQueryAndVerifyVehicleResults( "from Vehicle v fetch all properties left join fetch v.driver" );
|
||||
performQueryAndVerifyVehicleResults( "from Vehicle v left join fetch v.driver" );
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public void test3() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
List<Person> persons = (List<Person>) s.createCriteria( Person.class ).setFetchMode( "vehicle", FetchMode.JOIN ).list();
|
||||
for ( Person person : persons ) {
|
||||
if ( shouldHaveVehicle( person ) ) {
|
||||
assertNotNull( person.getVehicle() );
|
||||
assertNotNull( person.getVehicle().getDriver() );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public void test4() {
|
||||
List<Vehicle> vehicles;
|
||||
|
||||
try ( Session s = openSession() ) {
|
||||
vehicles = (List<Vehicle>) s.createCriteria( Vehicle.class ).setFetchMode( "driver", FetchMode.JOIN ).list();
|
||||
}
|
||||
|
||||
for ( Vehicle vehicle : vehicles ) {
|
||||
if ( shouldHaveDriver( vehicle ) ) {
|
||||
assertNotNull( vehicle.getDriver() );
|
||||
assertNotNull( vehicle.getDriver().getVehicle() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void performQueryAndVerifyPersonResults(String query) {
|
||||
List<Person> persons;
|
||||
try ( Session s = openSession() ) {
|
||||
persons = (List<Person>) s.createQuery( query ).list();
|
||||
}
|
||||
for ( Person person : persons ) {
|
||||
assertTrue( isInitialized( person ) );
|
||||
if ( shouldHaveVehicle( person ) ) {
|
||||
assertNotNull( person.getVehicle() );
|
||||
assertTrue( isInitialized( person.getVehicle() ) );
|
||||
assertNotNull( person.getVehicle().getDriver() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void performQueryAndVerifyVehicleResults(String query) {
|
||||
List<Vehicle> vehicles;
|
||||
try ( Session s = openSession() ) {
|
||||
vehicles = (List<Vehicle>) s.createQuery( query ).list();
|
||||
}
|
||||
for ( Vehicle vehicle : vehicles ) {
|
||||
if ( shouldHaveDriver( vehicle ) ) {
|
||||
assertNotNull( vehicle.getDriver() );
|
||||
assertNotNull( vehicle.getDriver().getVehicle() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldHaveVehicle(Person person) {
|
||||
return "Johnny".equals( person.name ) || "Ricky".equals( person.name );
|
||||
}
|
||||
|
||||
private boolean shouldHaveDriver(Vehicle vehicle) {
|
||||
return "Volkswagen Golf".equals( vehicle.name ) || "Subaru Impreza".equals( vehicle.name );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Person" )
|
||||
@Table( name = "PERSON" )
|
||||
private static class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToOne( optional = true, mappedBy = "driver", fetch = FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
Vehicle vehicle;
|
||||
|
||||
Person() {
|
||||
}
|
||||
|
||||
Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Vehicle getVehicle() {
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
void setVehicle(Vehicle vehicle) {
|
||||
this.vehicle = vehicle;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Vehicle" )
|
||||
@Table( name = "VEHICLE" )
|
||||
private static class Vehicle {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToOne( optional = true, fetch = FetchType.LAZY )
|
||||
Person driver;
|
||||
|
||||
Vehicle() {
|
||||
}
|
||||
|
||||
Vehicle(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Person getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
void setDriver(Person driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.HHH_10708;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Cascade;
|
||||
import org.hibernate.annotations.CascadeType;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-10708" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class UnexpectedDeleteTest1 extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private long fooId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{Foo.class, Bar.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Bar bar1 = new Bar();
|
||||
Bar bar2 = new Bar();
|
||||
Foo foo = new Foo();
|
||||
s.save( bar1 );
|
||||
s.save( bar2 );
|
||||
s.save( foo );
|
||||
bar1.foo = foo;
|
||||
bar2.foo = foo;
|
||||
fooId = foo.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Foo foo = s.get( Foo.class, fooId );
|
||||
|
||||
// accessing the collection results in an exception
|
||||
foo.bars.size();
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "BAR" )
|
||||
private static class Bar {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToOne
|
||||
@Cache( usage = CacheConcurrencyStrategy.READ_WRITE )
|
||||
Foo foo;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "FOO" )
|
||||
private static class Foo {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@OneToMany( orphanRemoval = true, mappedBy = "foo", targetEntity = Bar.class )
|
||||
@Cascade( CascadeType.ALL )
|
||||
Set<Bar> bars = new HashSet<>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.HHH_10708;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-10708" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class UnexpectedDeleteTest2 extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private Bar myBar;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{Foo.class, Bar.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Bar bar = new Bar();
|
||||
Foo foo1 = new Foo();
|
||||
Foo foo2 = new Foo();
|
||||
s.save( bar );
|
||||
s.save( foo1 );
|
||||
s.save( foo2 );
|
||||
|
||||
bar.foos.add( foo1 );
|
||||
bar.foos.add( foo2 );
|
||||
|
||||
myBar = bar;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.refresh( myBar );
|
||||
Assert.assertFalse( myBar.foos.isEmpty() );
|
||||
|
||||
// The issue is that currently, for some unknown reason, foos are deleted on flush
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Bar bar = s.get( Bar.class, myBar.id );
|
||||
Assert.assertFalse( bar.foos.isEmpty() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "BAR" )
|
||||
private static class Bar {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToMany( fetch = FetchType.LAZY, targetEntity = Foo.class )
|
||||
Set<Foo> foos = new HashSet<>();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "FOO" )
|
||||
private static class Foo {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.HHH_10708;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-10708" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class UnexpectedDeleteTest3 extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{Parent.class, Child.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child child = new Child();
|
||||
child.setId( 2L );
|
||||
s.save( child );
|
||||
|
||||
Parent parent = new Parent();
|
||||
parent.setId( 1L );
|
||||
parent.setNames( Collections.singleton( "name" ) );
|
||||
parent.addChild( child );
|
||||
|
||||
s.save( parent );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent parent = s.get( Parent.class, 1L );
|
||||
|
||||
Child child = new Child();
|
||||
child.setId( 1L );
|
||||
s.save( child );
|
||||
parent.addChild( child );
|
||||
|
||||
// We need to leave at least one attribute unfetchd
|
||||
//parent.getNames().size();
|
||||
s.save( parent );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent application = s.get( Parent.class, 1L );
|
||||
Assert.assertEquals( "Loaded Children collection has unexpected size", 2, application.getChildren().size() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
Long id;
|
||||
|
||||
@Id
|
||||
@Column( name = "id", unique = true, nullable = false )
|
||||
Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
Long id;
|
||||
Set<String> names;
|
||||
Set<Child> children;
|
||||
|
||||
@Id
|
||||
@Column( name = "id", unique = true, nullable = false )
|
||||
Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@ElementCollection
|
||||
Set<String> getNames() {
|
||||
return Collections.unmodifiableSet( names );
|
||||
}
|
||||
|
||||
void setNames(Set<String> secrets) {
|
||||
this.names = secrets;
|
||||
}
|
||||
|
||||
@ManyToMany( fetch = FetchType.LAZY, targetEntity = Child.class )
|
||||
Set<Child> getChildren() {
|
||||
return Collections.unmodifiableSet( children );
|
||||
}
|
||||
|
||||
void addChild(Child child) {
|
||||
if (children == null) {
|
||||
children = new HashSet<>();
|
||||
}
|
||||
children.add( child );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.Persister;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.tuple.NonIdentifierAttribute;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-9937")
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyBasicFieldNotInitializedTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private Long entityId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{TestEntity.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity entity = new TestEntity();
|
||||
entity.description = "desc";
|
||||
s.persist( entity );
|
||||
entityId = entity.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity entity = s.get( TestEntity.class, entityId );
|
||||
Assert.assertFalse( Hibernate.isPropertyInitialized( entity, "description" ) );
|
||||
|
||||
EntityPersister entityPersister = sessionFactory().getMetamodel().entityPersister( TestEntity.class );
|
||||
|
||||
boolean[] propertyLaziness = entityPersister.getPropertyLaziness();
|
||||
assertEquals( 1, propertyLaziness.length );
|
||||
assertTrue( propertyLaziness[0] );
|
||||
|
||||
// Make sure NonIdentifierAttribute#isLazy is consistent (HHH-10551)
|
||||
NonIdentifierAttribute[] properties = entityPersister.getEntityMetamodel().getProperties();
|
||||
assertEquals( 1, properties.length );
|
||||
assertTrue( properties[0].isLazy() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "TEST_ENTITY" )
|
||||
private static class TestEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String description;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.MapsId;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.Table;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11576" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyCollectionDeletedTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private Long postId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Post.class, Tag.class, AdditionalDetails.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Post post = new Post();
|
||||
|
||||
Tag tag1 = new Tag( "tag1" );
|
||||
Tag tag2 = new Tag( "tag2" );
|
||||
|
||||
Set<Tag> tagSet = new HashSet<>();
|
||||
tagSet.add( tag1 );
|
||||
tagSet.add( tag2 );
|
||||
post.tags = tagSet;
|
||||
|
||||
AdditionalDetails details = new AdditionalDetails();
|
||||
details.post = post;
|
||||
details.details = "Some data";
|
||||
post.additionalDetails = details;
|
||||
|
||||
postId = (Long) s.save( post );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Query query = s.createQuery( "from AdditionalDetails where id=" + postId );
|
||||
AdditionalDetails additionalDetails = (AdditionalDetails) query.getSingleResult();
|
||||
additionalDetails.details = "New data";
|
||||
s.persist( additionalDetails );
|
||||
|
||||
// additionalDetais.post.tags get deleted on commit
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Query query = s.createQuery( "from Post where id=" + postId );
|
||||
Post retrievedPost = (Post) query.getSingleResult();
|
||||
|
||||
assertFalse( "No tags found", retrievedPost.tags.isEmpty() );
|
||||
retrievedPost.tags.forEach( tag -> System.out.println( "Found tag: " + tag ) );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Tag" )
|
||||
@Table( name = "TAG" )
|
||||
private static class Tag {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Tag() {
|
||||
}
|
||||
|
||||
Tag(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Post" )
|
||||
@Table( name = "POST" )
|
||||
private static class Post {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToMany( cascade = CascadeType.ALL )
|
||||
Set<Tag> tags;
|
||||
|
||||
@OneToOne( fetch = FetchType.LAZY, mappedBy = "post", cascade = CascadeType.ALL )
|
||||
AdditionalDetails additionalDetails;
|
||||
}
|
||||
|
||||
@Entity( name = "AdditionalDetails" )
|
||||
@Table( name = "ADDITIONAL_DETAILS" )
|
||||
private static class AdditionalDetails {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String details;
|
||||
|
||||
@OneToOne( optional = false )
|
||||
@MapsId
|
||||
Post post;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.sameInstance;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.Hibernate.isPropertyInitialized;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Simple test for lazy collection handling in the new bytecode support.
|
||||
* Prior to HHH-10055 lazy collections were simply not handled. The tests
|
||||
* initially added for HHH-10055 cover the more complicated case of handling
|
||||
* lazy collection initialization outside of a transaction; that is a bigger
|
||||
* fix, and I first want to get collection handling to work here in general.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-10055" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyCollectionLoadingTest extends BaseCoreFunctionalTestCase {
|
||||
private static final int CHILDREN_SIZE = 10;
|
||||
private Long parentID;
|
||||
private Parent parent;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class, Child.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent parent = new Parent();
|
||||
parent.setChildren( new ArrayList<>() );
|
||||
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
|
||||
Child child = new Child();
|
||||
child.parent = parent;
|
||||
s.persist( child );
|
||||
}
|
||||
s.persist( parent );
|
||||
parentID = parent.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransaction() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent parent = s.load( Parent.class, parentID );
|
||||
assertThat( parent, notNullValue() );
|
||||
assertThat( parent, not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertThat( parent, not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( isPropertyInitialized( parent, "children" ) );
|
||||
checkDirtyTracking( parent );
|
||||
|
||||
List children1 = parent.children;
|
||||
List children2 = parent.children;
|
||||
|
||||
assertTrue( isPropertyInitialized( parent, "children" ) );
|
||||
checkDirtyTracking( parent );
|
||||
|
||||
assertThat( children1, sameInstance( children2 ) );
|
||||
assertThat( children1.size(), equalTo( CHILDREN_SIZE ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoTransaction() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
parent = s.load( Parent.class, parentID );
|
||||
assertThat( parent, notNullValue() );
|
||||
assertThat( parent, not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertThat( parent, not( instanceOf( HibernateProxy.class ) ) );
|
||||
assertFalse( isPropertyInitialized( parent, "children" ) );
|
||||
} );
|
||||
|
||||
List children1 = parent.children;
|
||||
List children2 = parent.children;
|
||||
|
||||
assertTrue( isPropertyInitialized( parent, "children" ) );
|
||||
|
||||
checkDirtyTracking( parent );
|
||||
assertThat( children1, sameInstance( children2 ) );
|
||||
assertThat( children1.size(), equalTo( CHILDREN_SIZE ) );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@OneToMany( mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
List<Child> children;
|
||||
|
||||
void setChildren(List<Child> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
Parent parent;
|
||||
|
||||
String name;
|
||||
|
||||
Child() {
|
||||
}
|
||||
|
||||
Child(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyLoadingIntegrationTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private static final int CHILDREN_SIZE = 10;
|
||||
private Long lastChildID;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class, Child.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent parent = new Parent();
|
||||
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
|
||||
Child child = new Child();
|
||||
// Association management should kick in here
|
||||
child.parent = parent;
|
||||
s.persist( child );
|
||||
lastChildID = child.id;
|
||||
}
|
||||
s.persist( parent );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child loadedChild = s.load( Child.class, lastChildID );
|
||||
checkDirtyTracking( loadedChild );
|
||||
|
||||
loadedChild.name = "Barrabas";
|
||||
checkDirtyTracking( loadedChild, "name" );
|
||||
|
||||
Parent loadedParent = loadedChild.parent;
|
||||
checkDirtyTracking( loadedChild, "name" );
|
||||
checkDirtyTracking( loadedParent );
|
||||
|
||||
List<Child> loadedChildren = new ArrayList<>( loadedParent.children );
|
||||
loadedChildren.remove( 0 );
|
||||
loadedChildren.remove( loadedChild );
|
||||
loadedParent.setChildren( loadedChildren );
|
||||
|
||||
Assert.assertNull( loadedChild.parent );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@OneToMany( mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
List<Child> children;
|
||||
|
||||
void setChildren(List<Child> children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
Parent parent;
|
||||
|
||||
String name;
|
||||
|
||||
Child() {
|
||||
}
|
||||
|
||||
Child(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyLoadingTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private static final int CHILDREN_SIZE = 10;
|
||||
private Long parentID;
|
||||
private Long lastChildID;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class, Child.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent parent = new Parent();
|
||||
for ( int i = 0; i < CHILDREN_SIZE; i++ ) {
|
||||
Child child = new Child( "Child #" + i );
|
||||
child.parent = parent;
|
||||
parent.addChild( child );
|
||||
s.persist( child );
|
||||
lastChildID = child.id;
|
||||
}
|
||||
s.persist( parent );
|
||||
parentID = parent.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child loadedChild = s.load( Child.class, lastChildID );
|
||||
|
||||
Object nameByReflection = getFieldByReflection( loadedChild, "name" );
|
||||
assertNotNull( "Non-lazy field 'name' was not loaded", nameByReflection );
|
||||
|
||||
Object parentByReflection = getFieldByReflection( loadedChild, "parent" );
|
||||
assertNull( "Lazy field 'parent' is initialized", parentByReflection );
|
||||
assertFalse( loadedChild instanceof HibernateProxy );
|
||||
|
||||
Parent loadedParent = loadedChild.parent;
|
||||
assertThat( loadedChild.name, notNullValue() );
|
||||
assertThat( loadedParent, notNullValue() );
|
||||
assertThat( loadedChild.parent, notNullValue() );
|
||||
|
||||
checkDirtyTracking( loadedChild );
|
||||
|
||||
parentByReflection = getFieldByReflection( loadedChild, "parent" );
|
||||
Object childrenByReflection = getFieldByReflection( loadedParent, "children" );
|
||||
assertNotNull( "Lazy field 'parent' is not loaded", parentByReflection );
|
||||
assertNull( "Lazy field 'children' is initialized", childrenByReflection );
|
||||
assertFalse( loadedParent instanceof HibernateProxy );
|
||||
assertEquals( parentID, loadedParent.id );
|
||||
|
||||
Collection<Child> loadedChildren = loadedParent.children;
|
||||
|
||||
checkDirtyTracking( loadedChild );
|
||||
checkDirtyTracking( loadedParent );
|
||||
|
||||
childrenByReflection = getFieldByReflection( loadedParent, "children" );
|
||||
assertNotNull( "Lazy field 'children' is not loaded", childrenByReflection );
|
||||
assertFalse( loadedChildren instanceof HibernateProxy );
|
||||
assertEquals( CHILDREN_SIZE, loadedChildren.size() );
|
||||
assertTrue( loadedChildren.contains( loadedChild ) );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@OneToMany( mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
List<Child> children;
|
||||
|
||||
void addChild(Child child) {
|
||||
if ( children == null ) {
|
||||
children = new ArrayList<>();
|
||||
}
|
||||
children.add( child );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
Parent parent;
|
||||
|
||||
String name;
|
||||
|
||||
Child() {
|
||||
}
|
||||
|
||||
Child(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||
import org.hibernate.event.spi.EventType;
|
||||
import org.hibernate.event.spi.LoadEvent;
|
||||
import org.hibernate.event.spi.LoadEventListener;
|
||||
import org.hibernate.jpa.event.internal.core.JpaFlushEventListener;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-10922" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
@CustomEnhancementContext( {EnhancerTestContext.class, LazyProxyOnEnhancedEntityTest.NoLazyLoadingContext.class} )
|
||||
public class LazyProxyOnEnhancedEntityTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private Long parentID;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class, Child.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
Child c = new Child();
|
||||
em.persist( c );
|
||||
|
||||
Parent parent = new Parent();
|
||||
parent.setChild( c );
|
||||
em.persist( parent );
|
||||
parentID = parent.getId();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
EventListenerRegistry registry = sessionFactory().getServiceRegistry().getService( EventListenerRegistry.class );
|
||||
registry.prependListeners( EventType.FLUSH, new JpaFlushEventListener() );
|
||||
registry.prependListeners( EventType.LOAD, new ImmediateLoadTrap() );
|
||||
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
|
||||
em.find( Parent.class, parentID );
|
||||
|
||||
// unwanted lazy load occurs on flush
|
||||
} );
|
||||
}
|
||||
|
||||
private static class ImmediateLoadTrap implements LoadEventListener {
|
||||
@Override
|
||||
public void onLoad(LoadEvent event, LoadType loadType) throws HibernateException {
|
||||
if ( IMMEDIATE_LOAD == loadType ) {
|
||||
String msg = loadType + ":" + event.getEntityClassName() + "#" + event.getEntityId();
|
||||
throw new RuntimeException( msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
@OneToOne( fetch = FetchType.LAZY
|
||||
)
|
||||
Child child;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Child getChild() {
|
||||
return child;
|
||||
}
|
||||
|
||||
public void setChild(Child child) {
|
||||
this.child = child;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Child() {
|
||||
// No-arg constructor necessary for proxy factory
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
public static class NoLazyLoadingContext extends EnhancerTestContext {
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.basic;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.Hibernate.isPropertyInitialized;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyBasicFieldAccessTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private LazyEntity entity;
|
||||
private Long entityId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{LazyEntity.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
LazyEntity entity = new LazyEntity();
|
||||
entity.setDescription( "desc" );
|
||||
s.persist( entity );
|
||||
entityId = entity.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity = s.get( LazyEntity.class, entityId );
|
||||
|
||||
Assert.assertFalse( isPropertyInitialized( entity, "description" ) );
|
||||
checkDirtyTracking( entity );
|
||||
|
||||
assertEquals( "desc", entity.getDescription() );
|
||||
assertTrue( isPropertyInitialized( entity, "description" ) );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity.setDescription( "desc1" );
|
||||
s.update( entity );
|
||||
|
||||
//Assert.assertFalse( Hibernate.isPropertyInitialized( entity, "description" ) );
|
||||
checkDirtyTracking( entity, "description" );
|
||||
|
||||
assertEquals( "desc1", entity.getDescription() );
|
||||
assertTrue( isPropertyInitialized( entity, "description" ) );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity = s.get( LazyEntity.class, entityId );
|
||||
assertEquals( "desc1", entity.getDescription() );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity.setDescription( "desc2" );
|
||||
LazyEntity mergedEntity = (LazyEntity) s.merge( entity );
|
||||
|
||||
// Assert.assertFalse( isPropertyInitialized( entity, "description" ) );
|
||||
checkDirtyTracking( mergedEntity, "description" );
|
||||
|
||||
assertEquals( "desc2", mergedEntity.getDescription() );
|
||||
assertTrue( isPropertyInitialized( mergedEntity, "description" ) );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
LazyEntity entity = s.get( LazyEntity.class, entityId );
|
||||
assertEquals( "desc2", entity.getDescription() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "LAZY_FIELD_ENTITY" )
|
||||
private static class LazyEntity {
|
||||
Long id;
|
||||
String description;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.basic;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.Hibernate.isPropertyInitialized;
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyBasicPropertyAccessTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private LazyEntity entity;
|
||||
|
||||
private Long entityId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{LazyEntity.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
LazyEntity entity = new LazyEntity();
|
||||
entity.description = "desc";
|
||||
s.persist( entity );
|
||||
entityId = entity.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void execute() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity = s.get( LazyEntity.class, entityId );
|
||||
|
||||
Assert.assertFalse( isPropertyInitialized( entity, "description" ) );
|
||||
checkDirtyTracking( entity );
|
||||
|
||||
assertEquals( "desc", entity.description );
|
||||
assertTrue( isPropertyInitialized( entity, "description" ) );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity.description = "desc1";
|
||||
s.update( entity );
|
||||
|
||||
// Assert.assertFalse( Hibernate.isPropertyInitialized( entity, "description" ) );
|
||||
checkDirtyTracking( entity, "description" );
|
||||
|
||||
assertEquals( "desc1", entity.description );
|
||||
assertTrue( isPropertyInitialized( entity, "description" ) );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity = s.get( LazyEntity.class, entityId );
|
||||
assertEquals( "desc1", entity.description );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
entity.description = "desc2";
|
||||
LazyEntity mergedEntity = (LazyEntity) s.merge( entity );
|
||||
|
||||
//Assert.assertFalse( Hibernate.isPropertyInitialized( entity, "description" ) );
|
||||
checkDirtyTracking( mergedEntity, "description" );
|
||||
|
||||
assertEquals( "desc2", mergedEntity.description );
|
||||
assertTrue( isPropertyInitialized( mergedEntity, "description" ) );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
LazyEntity entity = s.get( LazyEntity.class, entityId );
|
||||
assertEquals( "desc2", entity.description );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Access( AccessType.FIELD )
|
||||
@Table( name = "LAZY_PROPERTY_ENTITY" )
|
||||
private static class LazyEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String description;
|
||||
}
|
||||
}
|
118
hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/LazyInCacheTest.java
vendored
Normal file
118
hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/LazyInCacheTest.java
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.cache;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyInCacheTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private Long orderId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Order.class, Product.class, Tag.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
} );
|
||||
|
||||
Order order = new Order();
|
||||
Product product = new Product();
|
||||
order.products.add( product );
|
||||
order.data = "some data".getBytes( Charset.defaultCharset() );
|
||||
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
em.persist( product );
|
||||
em.persist( order );
|
||||
} );
|
||||
|
||||
orderId = order.id;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::sessionFactory, em -> {
|
||||
Order order = em.find( Order.class, orderId );
|
||||
Assert.assertEquals( 1, order.products.size() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "ORDER_TABLE" )
|
||||
@Cache( usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE )
|
||||
private static class Order {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.IDENTITY )
|
||||
Long id;
|
||||
|
||||
@OneToMany
|
||||
List<Product> products = new ArrayList<>();
|
||||
|
||||
@OneToMany
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
@Type( type = "org.hibernate.type.BinaryType" )
|
||||
byte[] data;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "PRODUCT" )
|
||||
private static class Product {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.IDENTITY )
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "TAG" )
|
||||
private static class Tag {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.IDENTITY )
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.group;
|
||||
|
||||
import org.hibernate.annotations.LazyGroup;
|
||||
import org.hibernate.annotations.LazyToOne;
|
||||
import org.hibernate.annotations.LazyToOneOption;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11155" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class LazyGroupTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{Child.class, Parent.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = new Child( "steve", "Hibernater" );
|
||||
Child c2 = new Child( "sally", "Joe Mama" );
|
||||
|
||||
Parent p1 = new Parent( "Hibernate" );
|
||||
Parent p2 = new Parent( "Swimming" );
|
||||
|
||||
c1.parent = p1;
|
||||
p1.children.add( c1 );
|
||||
|
||||
c1.alternateParent = p2;
|
||||
p2.alternateChildren.add( c1 );
|
||||
|
||||
c2.parent = p2;
|
||||
p2.children.add( c2 );
|
||||
|
||||
c2.alternateParent = p1;
|
||||
p1.alternateChildren.add( c2 );
|
||||
|
||||
s.save( p1 );
|
||||
s.save( p2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-10267" )
|
||||
public void testAccess() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c1, "name" );
|
||||
assertNotLoaded( c1, "nickName" );
|
||||
assertNotLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
|
||||
// Now lets access nickName which ought to initialize nickName and parent, but not alternateParent
|
||||
c1.getNickName();
|
||||
assertLoaded( c1, "nickName" );
|
||||
assertLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
assertEquals( "Hibernate", c1.parent.nombre );
|
||||
assertFalse( c1.parent instanceof HibernateProxy );
|
||||
|
||||
Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c2, "name" );
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertNotLoaded( c2, "alternateParent" );
|
||||
|
||||
// Now lets access alternateParent which ought to initialize alternateParent and nothing else
|
||||
c2.getAlternateParent();
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertLoaded( c2, "alternateParent" );
|
||||
assertEquals( "Hibernate", c2.alternateParent.nombre );
|
||||
assertFalse( c2.alternateParent instanceof HibernateProxy );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-11155" )
|
||||
public void testUpdate() {
|
||||
Parent p1New = new Parent();
|
||||
p1New.nombre = "p1New";
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c1, "name" );
|
||||
assertNotLoaded( c1, "nickName" );
|
||||
assertNotLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
|
||||
// Now lets update nickName which ought to initialize nickName and parent, but not alternateParent
|
||||
c1.nickName = "new nickName";
|
||||
assertLoaded( c1, "nickName" );
|
||||
assertNotLoaded( c1, "parent" );
|
||||
assertNotLoaded( c1, "alternateParent" );
|
||||
assertEquals( "Hibernate", c1.parent.nombre );
|
||||
assertFalse( c1.parent instanceof HibernateProxy );
|
||||
|
||||
// Now update c1.parent
|
||||
c1.parent.children.remove( c1 );
|
||||
c1.parent = p1New;
|
||||
p1New.children.add( c1 );
|
||||
} );
|
||||
|
||||
// verify updates
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult();
|
||||
assertEquals( "new nickName", c1.getNickName() );
|
||||
assertEquals( "p1New", c1.parent.nombre );
|
||||
assertFalse( c1.parent instanceof HibernateProxy );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult();
|
||||
|
||||
// verify the expected initial loaded state
|
||||
assertLoaded( c2, "name" );
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertNotLoaded( c2, "alternateParent" );
|
||||
|
||||
// Now lets access and update alternateParent which ought to initialize alternateParent and nothing else
|
||||
Parent p1 = c2.getAlternateParent();
|
||||
c2.alternateParent = p1New;
|
||||
assertNotLoaded( c2, "nickName" );
|
||||
assertNotLoaded( c2, "parent" );
|
||||
assertLoaded( c2, "alternateParent" );
|
||||
assertEquals( "p1New", c2.getAlternateParent().nombre );
|
||||
assertFalse( c2.getAlternateParent() instanceof HibernateProxy );
|
||||
|
||||
p1.alternateChildren.remove( c2 );
|
||||
p1New.alternateChildren.add( c2 );
|
||||
} );
|
||||
|
||||
// verify update
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult();
|
||||
assertEquals( "p1New", c2.getAlternateParent().nombre );
|
||||
} );
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.createQuery( "delete Child" ).executeUpdate();
|
||||
s.createQuery( "delete Parent" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
private void assertLoaded(Object owner, String name) {
|
||||
// NOTE we assume null == not-loaded
|
||||
Object fieldByReflection = getFieldByReflection( owner, name );
|
||||
assertNotNull( "Expecting field '" + name + "' to be loaded, but it was not", fieldByReflection );
|
||||
}
|
||||
|
||||
private void assertNotLoaded(Object owner, String name) {
|
||||
// NOTE we assume null == not-loaded
|
||||
Object fieldByReflection = getFieldByReflection( owner, name );
|
||||
assertNull( "Expecting field '" + name + "' to be not loaded, but it was", fieldByReflection );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Parent" )
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
String nombre;
|
||||
|
||||
@OneToMany( mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
List<Child> children = new ArrayList<>();
|
||||
|
||||
@OneToMany( mappedBy = "alternateParent", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
List<Child> alternateChildren = new ArrayList<>();
|
||||
|
||||
Parent() {
|
||||
}
|
||||
|
||||
Parent(String nombre) {
|
||||
this.nombre = nombre;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Child" )
|
||||
@Table( name = "CHILD" )
|
||||
private static class Child {
|
||||
|
||||
@Id
|
||||
@GeneratedValue( strategy = GenerationType.AUTO )
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String nickName;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
Parent parent;
|
||||
|
||||
@ManyToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
@LazyToOne( LazyToOneOption.NO_PROXY )
|
||||
@LazyGroup( "SECONDARY" )
|
||||
Parent alternateParent;
|
||||
|
||||
Child() {
|
||||
}
|
||||
|
||||
Child(String name, String nickName) {
|
||||
this.name = name;
|
||||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
Parent getAlternateParent() {
|
||||
return alternateParent;
|
||||
}
|
||||
|
||||
String getNickName() {
|
||||
return nickName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazy.group;
|
||||
|
||||
import org.hibernate.annotations.LazyGroup;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||
import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11155, HHH-11506" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
@CustomEnhancementContext( {EnhancerTestContext.class, SimpleLazyGroupUpdateTest.NoDirtyCheckingContext.class} )
|
||||
public class SimpleLazyGroupUpdateTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
public static final String REALLY_BIG_STRING = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{TestEntity.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
} );
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.save( new TestEntity( 1L, "entity 1", "blah", REALLY_BIG_STRING ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity entity = s.load( TestEntity.class, 1L );
|
||||
assertLoaded( entity, "name" );
|
||||
assertNotLoaded( entity, "lifeStory" );
|
||||
assertNotLoaded( entity, "reallyBigString" );
|
||||
|
||||
entity.lifeStory = "blah blah blah";
|
||||
assertLoaded( entity, "name" );
|
||||
assertLoaded( entity, "lifeStory" );
|
||||
assertNotLoaded( entity, "reallyBigString" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
TestEntity entity = s.load( TestEntity.class, 1L );
|
||||
|
||||
assertLoaded( entity, "name" );
|
||||
assertNotLoaded( entity, "lifeStory" );
|
||||
assertNotLoaded( entity, "reallyBigString" );
|
||||
assertEquals( "blah blah blah", entity.lifeStory );
|
||||
assertEquals( REALLY_BIG_STRING, entity.reallyBigString );
|
||||
} );
|
||||
}
|
||||
|
||||
private void assertLoaded(Object owner, String name) {
|
||||
// NOTE we assume null == not-loaded
|
||||
Object fieldByReflection = getFieldByReflection( owner, name );
|
||||
assertNotNull( "Expecting field '" + name + "' to be loaded, but it was not", fieldByReflection );
|
||||
}
|
||||
|
||||
private void assertNotLoaded(Object owner, String name) {
|
||||
// NOTE we assume null == not-loaded
|
||||
Object fieldByReflection = getFieldByReflection( owner, name );
|
||||
assertNull( "Expecting field '" + name + "' to be not loaded, but it was", fieldByReflection );
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.createQuery( "delete TestEntity" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "TestEntity" )
|
||||
@Table( name = "TEST_ENTITY" )
|
||||
private static class TestEntity {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
@LazyGroup( "grp1" )
|
||||
String lifeStory;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
@LazyGroup( "grp2" )
|
||||
String reallyBigString;
|
||||
|
||||
TestEntity() {
|
||||
}
|
||||
|
||||
TestEntity(Long id, String name, String lifeStory, String reallyBigString) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.lifeStory = lifeStory;
|
||||
this.reallyBigString = reallyBigString;
|
||||
}
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
public static class NoDirtyCheckingContext extends EnhancerTestContext {
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.lazyCache;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.Formula;
|
||||
import org.hibernate.cache.spi.entry.StandardCacheEntryImpl;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.cache.BaseRegion;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.hibernate.Hibernate.isPropertyInitialized;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class InitFromCacheTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private EntityPersister persister;
|
||||
|
||||
private Long documentID;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[]{Document.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" );
|
||||
configuration.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
} );
|
||||
|
||||
persister = sessionFactory().getMetamodel().entityPersister( Document.class );
|
||||
assertTrue( persister.hasCache() );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Document document = new Document( "HiA", "Hibernate book", "Hibernate is...." );
|
||||
s.persist( document );
|
||||
documentID = document.id;
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void execute() {
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Document d = (Document) s.createQuery( "from Document fetch all properties" ).uniqueResult();
|
||||
assertTrue( isPropertyInitialized( d, "text" ) );
|
||||
assertTrue( isPropertyInitialized( d, "summary" ) );
|
||||
|
||||
BaseRegion region = (BaseRegion) persister.getCacheAccessStrategy().getRegion();
|
||||
Object cacheKey = persister.getCacheAccessStrategy().generateCacheKey( d.id, persister, sessionFactory(), null );
|
||||
StandardCacheEntryImpl cacheEntry = (StandardCacheEntryImpl) region.getDataMap().get( cacheKey );
|
||||
assertNotNull( cacheEntry );
|
||||
} );
|
||||
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Document d = (Document) s.createCriteria( Document.class ).uniqueResult();
|
||||
assertFalse( isPropertyInitialized( d, "text" ) );
|
||||
assertFalse( isPropertyInitialized( d, "summary" ) );
|
||||
assertEquals( "Hibernate is....", d.text );
|
||||
assertTrue( isPropertyInitialized( d, "text" ) );
|
||||
assertTrue( isPropertyInitialized( d, "summary" ) );
|
||||
} );
|
||||
|
||||
assertEquals( 2, sessionFactory().getStatistics().getPrepareStatementCount() );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Document d = s.get( Document.class, documentID );
|
||||
assertFalse( isPropertyInitialized( d, "text" ) );
|
||||
assertFalse( isPropertyInitialized( d, "summary" ) );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity( name = "Document" )
|
||||
@Table( name = "DOCUMENT" )
|
||||
@Cacheable
|
||||
@Cache( usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, include = "non-lazy", region = "foo" )
|
||||
private static class Document {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
@Formula( "upper(name)" )
|
||||
String upperCaseName;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String summary;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
String text;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
Date lastTextModification;
|
||||
|
||||
Document() {
|
||||
}
|
||||
|
||||
Document(String name, String summary, String text) {
|
||||
this.lastTextModification = new Date();
|
||||
this.name = name;
|
||||
this.upperCaseName = name.toUpperCase( Locale.ROOT );
|
||||
this.summary = summary;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.merge;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class CompositeMergeTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
private long entityId;
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{ParentEntity.class, Address.class, Country.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
ParentEntity parent = new ParentEntity();
|
||||
parent.description = "desc";
|
||||
parent.address = new Address();
|
||||
parent.address.street = "Sesame street";
|
||||
parent.address.country = new Country();
|
||||
parent.address.country.name = "Suriname";
|
||||
parent.address.country.languages = Arrays.asList( "english", "spanish" );
|
||||
|
||||
parent.lazyField = new byte[100];
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.persist( parent );
|
||||
} );
|
||||
|
||||
checkDirtyTracking( parent );
|
||||
entityId = parent.id;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ParentEntity[] parent = new ParentEntity[3];
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
parent[0] = s.get( ParentEntity.class, entityId );
|
||||
} );
|
||||
|
||||
checkDirtyTracking( parent[0] );
|
||||
|
||||
parent[0].address.country.name = "Paraguai";
|
||||
|
||||
checkDirtyTracking( parent[0], "address.country" );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
parent[1] = (ParentEntity) s.merge( parent[0] );
|
||||
checkDirtyTracking( parent[0], "address.country" );
|
||||
checkDirtyTracking( parent[1], "address.country" );
|
||||
} );
|
||||
|
||||
checkDirtyTracking( parent[0], "address.country" );
|
||||
checkDirtyTracking( parent[1] );
|
||||
|
||||
parent[1].address.country.name = "Honduras";
|
||||
|
||||
checkDirtyTracking( parent[1], "address.country" );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.saveOrUpdate( parent[1] );
|
||||
checkDirtyTracking( parent[1], "address.country" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
parent[2] = s.get( ParentEntity.class, entityId );
|
||||
Assert.assertEquals( "Honduras", parent[2].address.country.name );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT_ENTITY" )
|
||||
private static class ParentEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String description;
|
||||
|
||||
@Embedded
|
||||
Address address;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
byte[] lazyField;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
@Table( name = "ADDRESS" )
|
||||
private static class Address {
|
||||
|
||||
String street;
|
||||
|
||||
@Embedded
|
||||
Country country;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
@Table( name = "COUNTRY" )
|
||||
private static class Country {
|
||||
|
||||
String name;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable( name = "languages", joinColumns = @JoinColumn( name = "id", referencedColumnName = "id" ) )
|
||||
List<String> languages;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.merge;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11459" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class MergeEnhancedEntityTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Person.class, PersonAddress.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.persist( new Person( 1L, "Sam" ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMerge() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person entity = s.find( Person.class, 1L );
|
||||
entity.name = "John";
|
||||
try {
|
||||
s.merge( entity );
|
||||
} catch ( RuntimeException e ) {
|
||||
fail( "Enhanced entity can't be merged: " + e.getMessage() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRefresh() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Person entity = s.find( Person.class, 1L );
|
||||
entity.name = "John";
|
||||
try {
|
||||
s.refresh( entity );
|
||||
} catch ( RuntimeException e ) {
|
||||
fail( "Enhanced entity can't be refreshed: " + e.getMessage() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PERSON" )
|
||||
private static class Person {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@Column( name = "name", length = 10, nullable = false )
|
||||
String name;
|
||||
|
||||
@OneToMany( fetch = FetchType.LAZY, mappedBy = "parent", orphanRemoval = true, cascade = CascadeType.ALL )
|
||||
List<PersonAddress> details = new ArrayList<>();
|
||||
|
||||
Person() {
|
||||
}
|
||||
|
||||
Person(Long id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "PERSON_ADDRESS" )
|
||||
private static class PersonAddress {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
@ManyToOne( optional = false, fetch = FetchType.LAZY )
|
||||
Person parent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.ondemandload;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hibernate.Hibernate.isPropertyInitialized;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Luis Barreiro
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-10055" )
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class OnDemandLoadTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[]{Store.class, Inventory.class, Product.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory( configuration -> {
|
||||
configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" );
|
||||
configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" );
|
||||
configuration.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Store store = new Store( 1L ).setName( "Acme Super Outlet" );
|
||||
s.persist( store );
|
||||
|
||||
Product product = new Product( "007" ).setName( "widget" ).setDescription( "FooBar" );
|
||||
s.persist( product );
|
||||
|
||||
store.addInventoryProduct( product ).setQuantity( 10L ).setStorePrice( new BigDecimal( 500 ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClosedSession() {
|
||||
sessionFactory().getStatistics().clear();
|
||||
Store[] store = new Store[1];
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
// first load the store, making sure it is not initialized
|
||||
store[0] = s.load( Store.class, 1L );
|
||||
assertNotNull( store[0] );
|
||||
assertFalse( isPropertyInitialized( store[0], "inventories" ) );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 0, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
} );
|
||||
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
|
||||
store[0].getInventories();
|
||||
assertTrue( isPropertyInitialized( store[0], "inventories" ) );
|
||||
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearedSession() {
|
||||
sessionFactory().getStatistics().clear();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
// first load the store, making sure collection is not initialized
|
||||
Store store = s.get( Store.class, 1L );
|
||||
assertNotNull( store );
|
||||
assertFalse( isPropertyInitialized( store, "inventories" ) );
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 0, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
|
||||
// then clear session and try to initialize collection
|
||||
s.clear();
|
||||
assertNotNull( store );
|
||||
assertFalse( isPropertyInitialized( store, "inventories" ) );
|
||||
store.getInventories().size();
|
||||
assertTrue( isPropertyInitialized( store, "inventories" ) );
|
||||
|
||||
// the extra Session is the temp Session needed to perform the init
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
|
||||
// clear Session again. The collection should still be recognized as initialized from above
|
||||
s.clear();
|
||||
assertNotNull( store );
|
||||
assertTrue( isPropertyInitialized( store, "inventories" ) );
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
|
||||
// lets clear the Session again and this time reload the Store
|
||||
s.clear();
|
||||
store = s.get( Store.class, 1L );
|
||||
s.clear();
|
||||
assertNotNull( store );
|
||||
|
||||
// collection should be back to uninitialized since we have a new entity instance
|
||||
assertFalse( isPropertyInitialized( store, "inventories" ) );
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
store.getInventories().size();
|
||||
assertTrue( isPropertyInitialized( store, "inventories" ) );
|
||||
|
||||
// the extra Session is the temp Session needed to perform the init
|
||||
assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
|
||||
// clear Session again. The collection should still be recognized as initialized from above
|
||||
s.clear();
|
||||
assertNotNull( store );
|
||||
assertTrue( isPropertyInitialized( store, "inventories" ) );
|
||||
assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() );
|
||||
assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "STORE" )
|
||||
private static class Store {
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
@OneToMany( mappedBy = "store", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
|
||||
List<Inventory> inventories = new ArrayList<>();
|
||||
|
||||
@Version
|
||||
Integer version;
|
||||
|
||||
Store() {
|
||||
}
|
||||
|
||||
Store(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Store setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
Inventory addInventoryProduct(Product product) {
|
||||
Inventory inventory = new Inventory( this, product );
|
||||
inventories.add( inventory );
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public List<Inventory> getInventories() {
|
||||
return Collections.unmodifiableList( inventories );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "INVENTORY" )
|
||||
private static class Inventory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@GenericGenerator( name = "increment", strategy = "increment" )
|
||||
Long id = -1L;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn( name = "STORE_ID" )
|
||||
Store store;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn( name = "PRODUCT_ID" )
|
||||
Product product;
|
||||
|
||||
Long quantity;
|
||||
|
||||
BigDecimal storePrice;
|
||||
|
||||
public Inventory() {
|
||||
}
|
||||
|
||||
public Inventory(Store store, Product product) {
|
||||
this.store = store;
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
Inventory setStore(Store store) {
|
||||
this.store = store;
|
||||
return this;
|
||||
}
|
||||
|
||||
Inventory setProduct(Product product) {
|
||||
this.product = product;
|
||||
return this;
|
||||
}
|
||||
|
||||
Inventory setQuantity(Long quantity) {
|
||||
this.quantity = quantity;
|
||||
return this;
|
||||
}
|
||||
|
||||
Inventory setStorePrice(BigDecimal storePrice) {
|
||||
this.storePrice = storePrice;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table( name = "PRODUCT" )
|
||||
private static class Product {
|
||||
@Id
|
||||
String id;
|
||||
|
||||
String name;
|
||||
|
||||
String description;
|
||||
|
||||
BigDecimal msrp;
|
||||
|
||||
@Version
|
||||
Long version;
|
||||
|
||||
Product() {
|
||||
}
|
||||
|
||||
Product(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
Product setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
Product setDescription(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
Product setMsrp(BigDecimal msrp) {
|
||||
this.msrp = msrp;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.otherentityentrycontext;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.ManagedEntity;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* This task tests ManagedEntity objects that are already associated with a different PersistenceContext.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class OtherEntityEntryContextTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{Parent.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
|
||||
// Create a Parent
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
s.persist( new Parent( 1L, "first" ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent p = s.get( Parent.class, 1L );
|
||||
assertTrue( ManagedEntity.class.isInstance( p ) );
|
||||
p.name = "second";
|
||||
|
||||
assertTrue( s.contains( p ) );
|
||||
|
||||
// open another session and evict p from the new session
|
||||
doInHibernate( this::sessionFactory, session2 -> {
|
||||
|
||||
// s2 should contains no entities
|
||||
assertFalse( session2.contains( p ) );
|
||||
|
||||
// evict should do nothing, since p is not associated with s2
|
||||
session2.evict( p );
|
||||
|
||||
assertFalse( session2.contains( p ) );
|
||||
assertNull( ( (SharedSessionContractImplementor) session2 ).getPersistenceContext().getEntry( p ) );
|
||||
|
||||
try {
|
||||
session2.update( p );
|
||||
fail( "should have failed because p is already associated with a PersistenceContext that is still open." );
|
||||
} catch ( HibernateException expected ) {
|
||||
// expected
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
Parent p = s.get( Parent.class, 1L );
|
||||
p.name = "third";
|
||||
|
||||
s.update( p );
|
||||
assertTrue( s.contains( p ) );
|
||||
s.evict( p );
|
||||
assertFalse( s.contains( p ) );
|
||||
|
||||
p = s.get( Parent.class, p.id );
|
||||
|
||||
assertEquals( "second", p.name );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@Table( name = "PARENT" )
|
||||
private static class Parent {
|
||||
|
||||
@Id
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
Parent() {
|
||||
}
|
||||
|
||||
Parent(Long id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* 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.test.bytecode.enhancement.pk;
|
||||
|
||||
import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.transaction.TransactionUtil;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Version;
|
||||
import java.io.Serializable;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* @author Gail Badner
|
||||
*/
|
||||
@RunWith( BytecodeEnhancerRunner.class )
|
||||
public class EmbeddedPKTest extends BaseCoreFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[]{WorkOrder.class, WorkOrderPK.class};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
buildSessionFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
TransactionUtil.doInHibernate( this::sessionFactory, s -> {
|
||||
s.persist( new WorkOrder() );
|
||||
} );
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Entity
|
||||
@IdClass( WorkOrderPK.class )
|
||||
@Table( name = "WORK_ORDER" )
|
||||
private static class WorkOrder {
|
||||
|
||||
@Id
|
||||
long id;
|
||||
|
||||
@Id
|
||||
long location;
|
||||
|
||||
int originalQuantity;
|
||||
|
||||
int completedQuantity;
|
||||
|
||||
@Temporal( TemporalType.TIMESTAMP )
|
||||
Calendar dueDate;
|
||||
|
||||
@Temporal( TemporalType.TIMESTAMP )
|
||||
Calendar startDate;
|
||||
|
||||
String assemblyId;
|
||||
|
||||
@Version
|
||||
long version;
|
||||
|
||||
WorkOrder() {
|
||||
this( "", 1, 0, Calendar.getInstance() );
|
||||
}
|
||||
|
||||
WorkOrder(String assemblyId, int origQty, int location, Calendar dueDate) {
|
||||
if ( origQty < 1 ) {
|
||||
throw new IllegalArgumentException( "WorkOrder can not be created with original quantity " + origQty + ". Must be > 0" );
|
||||
}
|
||||
if ( dueDate == null ) {
|
||||
throw new IllegalArgumentException( "WorkOrder can not be created with null due Date" );
|
||||
}
|
||||
this.assemblyId = assemblyId;
|
||||
this.originalQuantity = origQty;
|
||||
this.dueDate = dueDate;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
String getAssemblyId() {
|
||||
return assemblyId;
|
||||
}
|
||||
|
||||
void setAssemblyId(String assemblyId) {
|
||||
this.assemblyId = assemblyId;
|
||||
}
|
||||
|
||||
int getCompletedQuantity() {
|
||||
return completedQuantity;
|
||||
}
|
||||
|
||||
void setCompletedQuantity(int compQty) {
|
||||
this.completedQuantity = compQty;
|
||||
}
|
||||
|
||||
Calendar getDueDate() {
|
||||
return (Calendar) dueDate.clone();
|
||||
}
|
||||
|
||||
void setDueDate(Calendar dueDate) {
|
||||
this.dueDate = dueDate;
|
||||
}
|
||||
|
||||
int getOriginalQuantity() {
|
||||
return originalQuantity;
|
||||
}
|
||||
|
||||
void setOriginalQuantity(int originalQuantity) {
|
||||
this.originalQuantity = originalQuantity;
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
long getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
void setLocation(int location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
Calendar getStartDate() {
|
||||
return (Calendar) startDate.clone();
|
||||
}
|
||||
|
||||
void setStartDate(Calendar instance) {
|
||||
startDate = instance;
|
||||
}
|
||||
|
||||
long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
// Processing methods
|
||||
|
||||
boolean update() {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean setStatusCompleted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void advanceStatus() {
|
||||
}
|
||||
|
||||
void setStatusCancelled() {
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this == other || other != null && other instanceof WorkOrder && id == ( (WorkOrder) other ).id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) ( id ^ id >>> 32 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WorkOrder:[" + id + "]";
|
||||
}
|
||||
}
|
||||
|
||||
private static class WorkOrderPK implements Serializable {
|
||||
long id;
|
||||
long location;
|
||||
|
||||
WorkOrderPK() {
|
||||
}
|
||||
|
||||
public WorkOrderPK(int location, int id) {
|
||||
this.location = location;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public long getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
// --- //
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this == other || other != null && other instanceof WorkOrder && id == ( (WorkOrder) other ).id && location == ( (WorkOrder) other ).location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) ( 31 * ( id ^ id >>> 32 ) + ( location ^ location >>> 32 ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ package org.hibernate.test.bytecode.enhancement.tracker;
|
|||
|
||||
import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker;
|
||||
import org.hibernate.engine.spi.CompositeOwner;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -24,41 +23,46 @@ public class CompositeOwnerTrackerTest {
|
|||
public void testCompositeOwnerTracker() {
|
||||
|
||||
CompositeOwnerTracker tracker = new CompositeOwnerTracker();
|
||||
tracker.add("foo", new TestCompositeOwner());
|
||||
tracker.add( "foo", new TestCompositeOwner() );
|
||||
|
||||
tracker.callOwner(".street1");
|
||||
assertEquals(1, counter);
|
||||
tracker.add("bar", new TestCompositeOwner());
|
||||
tracker.callOwner(".city");
|
||||
assertEquals(3, counter);
|
||||
tracker.callOwner( ".street1" );
|
||||
assertEquals( 1, counter );
|
||||
tracker.add( "bar", new TestCompositeOwner() );
|
||||
tracker.callOwner( ".city" );
|
||||
assertEquals( 3, counter );
|
||||
|
||||
tracker.removeOwner("foo");
|
||||
tracker.removeOwner( "foo" );
|
||||
|
||||
tracker.callOwner(".country");
|
||||
assertEquals(4, counter);
|
||||
tracker.removeOwner("bar");
|
||||
tracker.callOwner( ".country" );
|
||||
assertEquals( 4, counter );
|
||||
tracker.removeOwner( "bar" );
|
||||
|
||||
tracker.callOwner(".country");
|
||||
tracker.callOwner( ".country" );
|
||||
|
||||
tracker.add("moo", new TestCompositeOwner());
|
||||
tracker.callOwner(".country");
|
||||
assertEquals(5, counter);
|
||||
tracker.add( "moo", new TestCompositeOwner() );
|
||||
tracker.callOwner( ".country" );
|
||||
assertEquals( 5, counter );
|
||||
}
|
||||
|
||||
class TestCompositeOwner implements CompositeOwner {
|
||||
|
||||
@Override
|
||||
public void $$_hibernate_trackChange(String attributeName) {
|
||||
if(counter == 0)
|
||||
assertEquals("foo.street1", attributeName);
|
||||
if(counter == 1)
|
||||
assertEquals("foo.city", attributeName);
|
||||
if(counter == 2)
|
||||
assertEquals("bar.city", attributeName);
|
||||
if(counter == 3)
|
||||
assertEquals("bar.country", attributeName);
|
||||
if(counter == 4)
|
||||
assertEquals("moo.country", attributeName);
|
||||
if ( counter == 0 ) {
|
||||
assertEquals( "foo.street1", attributeName );
|
||||
}
|
||||
if ( counter == 1 ) {
|
||||
assertEquals( "foo.city", attributeName );
|
||||
}
|
||||
if ( counter == 2 ) {
|
||||
assertEquals( "bar.city", attributeName );
|
||||
}
|
||||
if ( counter == 3 ) {
|
||||
assertEquals( "bar.country", attributeName );
|
||||
}
|
||||
if ( counter == 4 ) {
|
||||
assertEquals( "moo.country", attributeName );
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ package org.hibernate.test.bytecode.enhancement.tracker;
|
|||
import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker;
|
||||
import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker;
|
||||
import org.hibernate.bytecode.enhance.internal.tracker.SortedFieldTracker;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -24,69 +24,68 @@ public class DirtyTrackerTest {
|
|||
@Test
|
||||
public void testSimpleTracker() {
|
||||
DirtyTracker tracker = new SimpleFieldTracker();
|
||||
assertTrue(tracker.isEmpty());
|
||||
assertTrue(tracker.get().length == 0);
|
||||
assertTrue( tracker.isEmpty() );
|
||||
assertEquals( 0, tracker.get().length );
|
||||
|
||||
tracker.add("foo");
|
||||
assertFalse(tracker.isEmpty());
|
||||
assertArrayEquals(tracker.get(), new String[]{"foo"});
|
||||
tracker.add( "foo" );
|
||||
assertFalse( tracker.isEmpty() );
|
||||
assertArrayEquals( tracker.get(), new String[]{"foo"} );
|
||||
|
||||
tracker.clear();
|
||||
assertTrue(tracker.isEmpty());
|
||||
assertTrue(tracker.get().length == 0);
|
||||
assertTrue( tracker.isEmpty() );
|
||||
assertEquals( 0, tracker.get().length );
|
||||
|
||||
tracker.add("foo");
|
||||
tracker.add("bar");
|
||||
tracker.add("another.bar");
|
||||
tracker.add("foo");
|
||||
tracker.add("another.foo");
|
||||
tracker.add("another.bar");
|
||||
assertTrue(tracker.get().length == 4);
|
||||
tracker.add( "foo" );
|
||||
tracker.add( "bar" );
|
||||
tracker.add( "another.bar" );
|
||||
tracker.add( "foo" );
|
||||
tracker.add( "another.foo" );
|
||||
tracker.add( "another.bar" );
|
||||
assertEquals( 4, tracker.get().length );
|
||||
|
||||
tracker.suspend(true);
|
||||
tracker.add("one more");
|
||||
assertTrue(tracker.get().length == 4);
|
||||
tracker.suspend( true );
|
||||
tracker.add( "one more" );
|
||||
assertEquals( 4, tracker.get().length );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSortedTracker() {
|
||||
DirtyTracker tracker = new SortedFieldTracker();
|
||||
assertTrue(tracker.isEmpty());
|
||||
assertTrue(tracker.get().length == 0);
|
||||
assertTrue( tracker.isEmpty() );
|
||||
assertEquals( 0, tracker.get().length );
|
||||
|
||||
tracker.add("foo");
|
||||
assertFalse(tracker.isEmpty());
|
||||
assertArrayEquals(tracker.get(), new String[]{"foo"});
|
||||
tracker.add( "foo" );
|
||||
assertFalse( tracker.isEmpty() );
|
||||
assertArrayEquals( tracker.get(), new String[]{"foo"} );
|
||||
|
||||
tracker.clear();
|
||||
assertTrue(tracker.isEmpty());
|
||||
assertTrue(tracker.get().length == 0);
|
||||
assertTrue( tracker.isEmpty() );
|
||||
assertEquals( 0, tracker.get().length );
|
||||
|
||||
tracker.add("foo");
|
||||
tracker.add("bar");
|
||||
tracker.add("another.bar");
|
||||
tracker.add("foo");
|
||||
tracker.add("another.foo");
|
||||
tracker.add("another.bar");
|
||||
assertTrue(tracker.get().length == 4);
|
||||
tracker.add( "foo" );
|
||||
tracker.add( "bar" );
|
||||
tracker.add( "another.bar" );
|
||||
tracker.add( "foo" );
|
||||
tracker.add( "another.foo" );
|
||||
tracker.add( "another.bar" );
|
||||
assertEquals( 4, tracker.get().length );
|
||||
|
||||
// we the algorithm for this implementation relies on the fact that the array is kept sorted, so let's check it really is
|
||||
assertTrue(isSorted(tracker.get()));
|
||||
// the algorithm for this implementation relies on the fact that the array is kept sorted, so let's check it really is
|
||||
assertTrue( isSorted( tracker.get() ) );
|
||||
|
||||
tracker.suspend(true);
|
||||
tracker.add("one more");
|
||||
assertTrue(tracker.get().length == 4);
|
||||
tracker.suspend( true );
|
||||
tracker.add( "one more" );
|
||||
assertEquals( 4, tracker.get().length );
|
||||
}
|
||||
|
||||
private boolean isSorted(String[] arr) {
|
||||
for (int i = 1; i < arr.length; i++) {
|
||||
if (arr[i - 1].compareTo(arr[i]) > 0) {
|
||||
for ( int i = 1; i < arr.length; i++ ) {
|
||||
if ( arr[i - 1].compareTo( arr[i] ) > 0 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue