<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ 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>.
  -->
<chapter xml:id="BytecodeEnhancement"
         version="5.0"
         xml:lang="en"
         xmlns="http://docbook.org/ns/docbook"
         xmlns:xi="http://www.w3.org/2001/XInclude"
>

    <info>
        <title>Bytecode Enhancement</title>
        <abstract>
            <para>
                Bytecode enhancement is the process of manipulating the bytecode (.class) representation of
                a class for some purpose.  This chapter explores Hibernate's ability to perform bytecode
                enhancement.
            </para>
        </abstract>
    </info>


    <sidebar>
        <para>
            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.  Hibernate
            3.x saw the first attempts at bytecode enhancement support in Hibernate.  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.
        </para>
    </sidebar>

    <section>
        <title>Capabilities</title>
        <para>
            Hibernate supports the enhancement of an application's Java domain model for the purpose of adding
            various persistence-related capabilities directly into the class, including...
        </para>

        <section>
            <title>Lazy attribute loading</title>
            <para>
                Think of this as partial loading support.  Essentially you can
                tell Hibernate that only part(s) of an entity should be loaded and when the other part(s)
                should be loaded.  Note that this is very much different from proxy-based idea of lazy loading
                which is entity-centric where the entity's state is loaded at once as needed.  With bytecode
                enhancement, individual attributes or groups of attributes are loaded as needed.
            </para>

            <para>
                Lazy attributes can be designated to be loaded together; this is called a "lazy group".
                By default all singular attributes are part of a single group, meaning that when one lazy singular
                attribute is accessed all lazy singular attributes are loaded.  Lazy plural attributes, by default,
                are each a lazy group by themselves.  This behavior is explicitly controllable through the
                <interfacename>@org.hibernate.annotations.LazyGroup</interfacename> annotation.
            </para>

            <example>
                <title>@LazyGroup example</title>
                <programlisting role="JAVA"><xi:include parse="text" href="extras/LazyGroupExample.java" /></programlisting>
            </example>

            <para>
                In the above example we have 2 lazy attributes: accountsPayableXrefId and image.  Each is part of
                a different fetch group (accountsPayableXrefId is part of the default fetch group). Which means
                that accessing accountsPayableXrefId will not force the loading of image, and vice-versa.
            </para>

            <note>
                <para>
                    As a hopefully temporary legacy hold-over, it is currently required that all lazy singular
                    associations (many-to-one and one-to-one) also include <literal>@LazyToOne(LazyToOneOption.NO_PROXY)</literal>.
                    The plan is to relax that requirement later.
                </para>
            </note>
        </section>

        <section>
            <title>In-line dirty tracking</title>
            <para>
                Historically Hibernate only supported diff-based dirty calculation for determining which
                entities in a persistence context have changed.  This essentially means that Hibernate
                would keep track of the last known state of an entity in regards to the database (typically
                the last read or write).  Then, as part of flushing the persistence context, Hibernate would walk
                every entity associated with the persistence context and check its current state against that
                "last known database state".  This is by far the most thorough approach to dirty checking
                because it accounts for data-types that can change their internal state
                (<classname>java.util.Date</classname> is the prime example of this).  However, in a persistence
                context with a large number of associated entities it can also be a performance-inhibiting
                approach.
            </para>
            <para>
                If your application does not need to care about "internal state changing data-type" use cases,
                bytecode-enhanced dirty tracking might be a worthwhile alternative to consider, especially in
                terms of performance.  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.  Come flush time, Hibernate simply asks your entity what has
                changed rather that having to perform the state-diff calculations.
            </para>
        </section>

        <section>
            <title>Bi-directional association management</title>
            <para>
                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:
            </para>
            <example>
                <title>Incorrect normal Java usage</title>
                <programlisting role="JAVA"><xi:include href="extras/BiDirManagementNormalJavaIncorrect.java" parse="text" /></programlisting>
            </example>
            <para>
                This blows up in normal Java usage.  The correct normal Java usage is:
            </para>
            <example>
                <title>Correct normal Java usage</title>
                <programlisting role="JAVA"><xi:include href="extras/BiDirManagementNormalJavaCorrect.java" parse="text" /></programlisting>
            </example>
            <para>
                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.
            </para>
        </section>

        <section>
            <title>Internal performance optimizations</title>
            <para>
                Additionally we use the enhancement process to add some additional code that allows us to
                optimized certain performance characteristics of the persistence context.  These are hard to
                discuss without diving into a discussion of Hibernate internals.
            </para>
        </section>
    </section>

    <section>
        <title>Performing enhancement</title>
        <para>
            There are two methods to perform bytecode enhancement.  It can be done during run time or build time,
            using one of the provided plugins for build automation tools.  Each capability must be enabled
            independently, using the respective property:
            <variablelist>
                <varlistentry>
                    <term>enableLazyInitialization</term>
                    <listitem>
                        <para>
                            Whether enhancement for lazy attribute loading should be done.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>enableDirtyTracking</term>
                    <listitem>
                        <para>
                            Whether enhancement for self-dirty tracking should be done.
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>enableAssociationManagement</term>
                    <listitem>
                        <para>
                            Whether enhancement for bi-directional association management should be done.
                        </para>
                    </listitem>
                </varlistentry>
            </variablelist>
        </para>
        <para>
            Ultimately all enhancement is handled by the <code>org.hibernate.bytecode.enhance.spi.Enhancer</code> class.
            Custom means to enhancement can certainly be crafted on top of Enhancer, but that is beyond the scope of
            this guide.  Here we will focus on the means Hibernate already exposes for performing these enhancements.
        </para>

        <section>
            <title>Run-time enhancement</title>
            <para>
                Currently run-time enhancement of the domain model is only supported in managed JPA
                environments following the JPA defined SPI for performing class transformations. Even then, this
                support is disabled by default.  To enable run-time enhancement, turn on one or more of the following
                properties in the persistent unit:
                <example>
                    <title>Example persistence.xml</title>
                    <programlisting role="XML"><xi:include href="extras/persistence-example.xml" parse="text"/></programlisting>
                </example>
            </para>
            <para>
                Also, at the moment only annotated classes are supported for run-time enhancement.  Only the
                classes declared in the persistent unit will be enhanced.
            </para>
        </section>

        <section>
            <title>Build-time enhancement</title>
            <para>
                Hibernate provides plugins for Gradle and Maven build tools.
            </para>

            <section>
                <title>Gradle plugin</title>
                <para>
                    Hibernate provides a Gradle plugin that is capable of providing build-time enhancement of the
                    domain model as they are compiled as part of a Gradle build. To use the plugin a project would
                    first need to apply it.
                </para>
                <example>
                    <title>Apply the Gradle plugin</title>
                    <programlisting role="JAVA"><xi:include href="extras/gradle-example.gradle" parse="text"/></programlisting>
                </example>
                <para>
                    The configuration that is available is exposed through a registered Gradle DSL extension. The default
                    value for all configuration settings is <literal>false</literal>.
                </para>
                <para>
                    The <code>enhance { }</code> block is required in order for enhancement to occur. Enhancement
                    is disabled by default in preparation for additions capabilities (hbm2ddl, etc) in the plugin.
                </para>
            </section>

            <section>
                <title>Maven plugin</title>
                <para>
                    Hibernate provides a Maven plugin capable of providing build-time enhancement of the
                    domain model as they are compiled as part of a Maven build.  The configuration has the same properties
                    as the Gradle plugin and the default value for all settings is also <literal>false</literal>.
                </para>
                <para>
                    The Maven plugin supports one additional configuration settings: failOnError, which controls
                    what happens in case of an error.  Default behavior is to fail the build, but it can be set so
                    that only a warning is issued.
                </para>
                <example>
                    <title>Apply the Maven plugin</title>
                    <programlisting role="XML"><xi:include href="extras/maven-example.pom" parse="text"/></programlisting>
                </example>
            </section>
        </section>
    </section>

</chapter>