Migrate Bytecode Enhancement User Guide chapter extras to test folder
This commit is contained in:
parent
96c96f2e94
commit
cd9ff725ae
|
@ -224,6 +224,11 @@ To substitute the `persistence.xml` file, Hibernate offers the `PersistenceUnitI
|
|||
[[bootstrap-native-EntityManagerFactory-example]]
|
||||
.Proprietary bootstrapped `EntityManagerFactory`
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/BootstrapTest.java[tags=bootstrap-native-PersistenceUnitInfoImpl-example]
|
||||
----
|
||||
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/BootstrapTest.java[tags=bootstrap-native-EntityManagerFactory-example]
|
||||
|
|
|
@ -26,7 +26,7 @@ COMMIT:: The `Session` tries to delay the flush until the current `Transaction`
|
|||
MANUAL:: The `Session` flushing is delegated to the application, which must call `Session.flush()` explicitly in order to apply the persistence context changes.
|
||||
|
||||
[[flushing-auto]]
|
||||
== `AUTO` flush
|
||||
=== `AUTO` flush
|
||||
|
||||
By default, Hibernate uses the `AUTO` flush mode which triggers a flush in the following circumstances:
|
||||
|
||||
|
@ -34,7 +34,7 @@ By default, Hibernate uses the `AUTO` flush mode which triggers a flush in the f
|
|||
* prior to executing a JPQL/HQL query that overlaps with the queued entity actions
|
||||
* before executing any native SQL query that has no registered synchronization
|
||||
|
||||
=== `AUTO` flush on commit
|
||||
==== `AUTO` flush on commit
|
||||
|
||||
In the following example, an entity is persisted and then the transaction is committed.
|
||||
|
||||
|
@ -61,7 +61,7 @@ The `IDENTITY` generator must execute the insert right after calling `persist()`
|
|||
For details, see the discussion of generators in <<chapters/domain/identifiers.adoc#identifiers,_Identifier generators_>>.
|
||||
====
|
||||
|
||||
=== `AUTO` flush on JPQL/HQL query
|
||||
==== `AUTO` flush on JPQL/HQL query
|
||||
|
||||
A flush may also be triggered when executing an entity query.
|
||||
|
||||
|
@ -108,7 +108,7 @@ include::{extrasdir}/flushing-auto-flush-jpql-overlap-example.sql[]
|
|||
|
||||
This time, the flush was triggered by a JPQL query because the pending entity persist action overlaps with the query being executed.
|
||||
|
||||
=== `AUTO` flush on native SQL query
|
||||
==== `AUTO` flush on native SQL query
|
||||
|
||||
When executing a native SQL query, a flush is always triggered when using the `EntityManager` API.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[[BytecodeEnhancement]]
|
||||
=== Bytecode Enhancement
|
||||
:sourcedir: extras
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/pc
|
||||
|
||||
Hibernate "grew up" not supporting bytecode enhancement at all.
|
||||
At that time, Hibernate only supported proxy-based for lazy loading and always used diff-based dirty calculation.
|
||||
|
@ -8,6 +8,7 @@ Hibernate 3.x saw the first attempts at bytecode enhancement support in Hibernat
|
|||
We consider those initial attempts (up until 5.0) completely as an incubation.
|
||||
The support for bytecode enhancement in 5.0 onward is what we are discussing here.
|
||||
|
||||
[[BytecodeEnhancement-capabilities]]
|
||||
==== Capabilities
|
||||
|
||||
Hibernate supports the enhancement of an application Java domain model for the purpose of adding various persistence-related capabilities directly into the class.
|
||||
|
@ -25,11 +26,12 @@ By default, all singular attributes are part of a single group, meaning that whe
|
|||
Lazy plural attributes, by default, are each a lazy group by themselves.
|
||||
This behavior is explicitly controllable through the `@org.hibernate.annotations.LazyGroup` annotation.
|
||||
|
||||
[[BytecodeEnhancement-lazy-loading-example]]
|
||||
.`@LazyGroup` example
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/LazyGroupExample.java[]
|
||||
include::{sourcedir}/BytecodeEnhancementTest.java[tags=BytecodeEnhancement-lazy-loading-example]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -56,31 +58,44 @@ If your application does not need to care about "internal state changing data-ty
|
|||
In this approach Hibernate will manipulate the bytecode of your classes to add "dirty tracking" directly to the entity, allowing the entity itself to keep track of which of its attributes have changed.
|
||||
During flush time, Hibernate simply asks your entity what has changed rather that having to perform the state-diff calculations.
|
||||
|
||||
===== Bi-directional association management
|
||||
[[BytecodeEnhancement-dirty-tracking-bidirectional]]
|
||||
===== Bidirectional association management
|
||||
|
||||
Hibernate strives to keep your application as close to "normal Java usage" (idiomatic Java) as possible.
|
||||
Consider a domain model with a normal Order/LineItem bi-directional association:
|
||||
Consider a domain model with a normal `Person`/`Book` bidirectional association:
|
||||
|
||||
[[BytecodeEnhancement-dirty-tracking-bidirectional-example]]
|
||||
.Bidirectional association
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/BytecodeEnhancementTest.java[tags=BytecodeEnhancement-dirty-tracking-bidirectional-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[BytecodeEnhancement-dirty-tracking-bidirectional-incorrect-usage-example]]
|
||||
.Incorrect normal Java usage
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/BiDirManagementNormalJavaIncorrect.java[]
|
||||
include::{sourcedir}/BytecodeEnhancementTest.java[tags=BytecodeEnhancement-dirty-tracking-bidirectional-incorrect-usage-example]
|
||||
----
|
||||
====
|
||||
|
||||
This blows up in normal Java usage. The correct normal Java usage is:
|
||||
|
||||
[[BytecodeEnhancement-dirty-tracking-bidirectional-correct-usage-example]]
|
||||
.Correct normal Java usage
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/BiDirManagementNormalJavaCorrect.java[]
|
||||
include::{sourcedir}/BytecodeEnhancementTest.java[tags=BytecodeEnhancement-dirty-tracking-bidirectional-correct-usage-example]
|
||||
----
|
||||
====
|
||||
|
||||
Bytecode-enhanced bi-directional association management makes that first example work by managing the "other side" of a bi-directional association whenever one side is manipulated.
|
||||
|
||||
[[BytecodeEnhancement-dirty-tracking-optimizations]]
|
||||
===== Internal performance optimizations
|
||||
|
||||
Additionally we use the enhancement process to add some additional code that allows us to optimized certain performance characteristics of the persistence context.
|
||||
|
@ -111,7 +126,7 @@ To use the plugin a project would first need to apply it:
|
|||
====
|
||||
[source,gradle]
|
||||
----
|
||||
include::{sourcedir}/gradle-example.gradle[]
|
||||
include::extras/gradle-example.gradle[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -139,9 +154,7 @@ Default behavior is to fail the build, but it can be set so that only a warning
|
|||
====
|
||||
[source,xml]
|
||||
----
|
||||
include::{sourcedir}/maven-example.pom[]
|
||||
include::extras/maven-example.pom[]
|
||||
----
|
||||
====
|
||||
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/pc
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
Order order = new Order();
|
||||
LineItem lineItem = new LineItem();
|
||||
order.getLineItems().add( lineItem );
|
||||
lineItem.setOrder( order );
|
||||
|
||||
// Now this is OK...
|
||||
lineItem.getOrder.getName();
|
|
@ -1,6 +0,0 @@
|
|||
Order order = new Order();
|
||||
LineItem lineItem = new LineItem();
|
||||
order.getLineItems().add( lineItem );
|
||||
|
||||
// This blows up ( NPE ) in normal Java usage
|
||||
lineItem.getOrder.getName();
|
|
@ -1,10 +0,0 @@
|
|||
javax.persistence.PersistenceUtil jpaUtil = javax.persistence.Persistence.getPersistenceUtil();
|
||||
if( jpaUtil.isLoaded(customer.getAddress() ){
|
||||
//display address if loaded
|
||||
}
|
||||
if( jpaUtil.isLoaded(customer.getOrders() )) ){
|
||||
//display orders if loaded
|
||||
}
|
||||
if( jpaUtil.isLoaded(customer,"detailedBio" ) ){
|
||||
//display property detailedBio if loaded
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
@Entity
|
||||
public class Customer {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
private UUID accountsPayableXrefId;
|
||||
|
||||
@Lob
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
@LazyGroup( "lobs" )
|
||||
private Blob image;
|
||||
|
||||
...
|
||||
|
||||
}
|
|
@ -362,8 +362,7 @@ public class BootstrapTest {
|
|||
}
|
||||
}
|
||||
|
||||
//tag::bootstrap-native-EntityManagerFactory-example[]
|
||||
|
||||
//tag::bootstrap-native-PersistenceUnitInfoImpl-example[]
|
||||
public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
|
||||
|
||||
private final String persistenceUnitName;
|
||||
|
@ -486,5 +485,5 @@ public class BootstrapTest {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
//end::bootstrap-native-EntityManagerFactory-example[]
|
||||
//end::bootstrap-native-PersistenceUnitInfoImpl-example[]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* 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.userguide.pc;
|
||||
|
||||
import java.sql.Blob;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.annotations.LazyGroup;
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BytecodeEnhancementTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class,
|
||||
Book.class,
|
||||
Customer.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::BytecodeEnhancement-dirty-tracking-bidirectional-incorrect-usage-example[]
|
||||
Person person = new Person();
|
||||
person.setName( "John Doe" );
|
||||
|
||||
Book book = new Book();
|
||||
person.getBooks().add( book );
|
||||
try {
|
||||
book.getAuthor().getName();
|
||||
}
|
||||
catch (NullPointerException expected) {
|
||||
// This blows up ( NPE ) in normal Java usage
|
||||
}
|
||||
//end::BytecodeEnhancement-dirty-tracking-bidirectional-incorrect-usage-example[]
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::BytecodeEnhancement-dirty-tracking-bidirectional-correct-usage-example[]
|
||||
Person person = new Person();
|
||||
person.setName( "John Doe" );
|
||||
|
||||
Book book = new Book();
|
||||
person.getBooks().add( book );
|
||||
book.setAuthor( person );
|
||||
|
||||
book.getAuthor().getName();
|
||||
//end::BytecodeEnhancement-dirty-tracking-bidirectional-correct-usage-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::BytecodeEnhancement-lazy-loading-example[]
|
||||
@Entity
|
||||
public class Customer {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
private UUID accountsPayableXrefId;
|
||||
|
||||
@Lob
|
||||
@Basic( fetch = FetchType.LAZY )
|
||||
@LazyGroup( "lobs" )
|
||||
private Blob image;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public UUID getAccountsPayableXrefId() {
|
||||
return accountsPayableXrefId;
|
||||
}
|
||||
|
||||
public void setAccountsPayableXrefId(UUID accountsPayableXrefId) {
|
||||
this.accountsPayableXrefId = accountsPayableXrefId;
|
||||
}
|
||||
|
||||
public Blob getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(Blob image) {
|
||||
this.image = image;
|
||||
}
|
||||
}
|
||||
//end::BytecodeEnhancement-lazy-loading-example[]
|
||||
|
||||
//tag::BytecodeEnhancement-dirty-tracking-bidirectional-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(mappedBy = "author")
|
||||
private List<Book> books = new ArrayList<>( );
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Book> getBooks() {
|
||||
return books;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Book")
|
||||
public static class Book {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@NaturalId
|
||||
private String isbn;
|
||||
|
||||
@ManyToOne
|
||||
private Person author;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Person getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Person author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public String getIsbn() {
|
||||
return isbn;
|
||||
}
|
||||
|
||||
public void setIsbn(String isbn) {
|
||||
this.isbn = isbn;
|
||||
}
|
||||
}
|
||||
//end::BytecodeEnhancement-dirty-tracking-bidirectional-example[]
|
||||
}
|
|
@ -327,8 +327,6 @@ public class PersistenceContextTest extends BaseEntityManagerFunctionalTestCase
|
|||
//end::pc-merge-visualize-example[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
|
Loading…
Reference in New Issue