<style>
/* Changing the layout to use less space for mobiles */
@media screen and (max-device-width: 480px), screen and (-webkit-min-device-pixel-ratio: 2) {
    #email-body { min-width: 30em !important; }
    #email-page { padding: 8px !important; }
    #email-banner { padding: 8px 8px 0 8px !important; }
    #email-avatar { margin: 1px 8px 8px 0 !important; padding: 0 !important; }
    #email-fields { padding: 0 8px 8px 8px !important; }
    #email-gutter { width: 0 !important; }
}
</style>
<div id="email-body">
<table id="email-wrap" align="center" border="0" cellpadding="0" cellspacing="0" style="background-color:#f0f0f0;color:#000000;width:100%;">
    <tr valign="top">
        <td id="email-page" style="padding:16px !important;">
            <table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color:#ffffff;border:1px solid #bbbbbb;color:#000000;width:100%;">
                <tr valign="top">
                    <td bgcolor="#3e4c4e" style="background-color:#3e4c4e;color:#ffffff;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;line-height:1;"><img src="https://www.jboss.org/dms/hibernate/images/jira/jiraheader_hibernate.png" alt="" style="vertical-align:top;" /></td>
                </tr><tr valign="top">
    <td id="email-banner" style="padding:32px 32px 0 32px;">

                
                    <table align="left" border="0" cellpadding="0" cellspacing="0" width="100%" style="width:100%;">
    <tr valign="top">
        <td style="color:#505050;font-family:Arial,FreeSans,Helvetica,sans-serif;padding:0;">
                                        <img id="email-avatar" src="https://secure.gravatar.com/avatar/df12d7792bd3b7be3a4edf12cabd58cb?d=mm&s=48" alt="" height="48" width="48" border="0" align="left" style="padding:0;margin: 0 16px 16px 0;" />
                        <div id="email-action" style="padding: 0 0 8px 0;font-size:12px;line-height:18px;">
                                    <a class="user-hover" rel="steve" id="email_steve" href="https://hibernate.atlassian.net/secure/ViewProfile.jspa?name=steve" style="color:#6c797f;">Steve Ebersole</a>
     commented on <img src="https://hibernate.atlassian.net/images/icons/issuetypes/task_agile.png" height="16" width="16" border="0" align="absmiddle" alt="Technical task"> <a style='color:#6c797f;text-decoration:none;' href='https://hibernate.atlassian.net/browse/HHH-8354'>HHH-8354</a>
            </div>
                        <div id="email-summary" style="font-size:16px;line-height:20px;padding:2px 0 16px 0;">
                <a style='color:#6c797f;text-decoration:none;' href='https://hibernate.atlassian.net/browse/HHH-8354'><strong>New dirty-checking options based on bytecode enhancement</strong></a>
            </div>
                    </td>
    </tr>
</table>
    </td>
</tr>
<tr valign="top">
    <td id="email-fields" style="padding:0 32px 32px 32px;">
        <table border="0" cellpadding="0" cellspacing="0" style="padding:0;text-align:left;width:100%;" width="100%">
            <tr valign="top">
                <td id="email-gutter" style="width:64px;white-space:nowrap;"></td>
                <td>
                    <table border="0" cellpadding="0" cellspacing="0" width="100%">
                        <tr valign="top">
    <td colspan="2" style="color:#000000;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:12px;padding:0 0 16px 0;width:100%;">
        <div class="comment-block" style="background-color:#edf5ff;border:1px solid #dddddd;color:#000000;padding:12px;"><blockquote>
<p>for the hook in, the piece im missing i think is where/which part of hibernate to i hook this into. ill look more into the generateFieldWriter later tonight, the only thing i remember it doing atm is check if the hibernate interceptor exists and then call writeObject or something.</p></blockquote>

<p>This is all within <tt>Enhancer</tt>.  I think maybe its good to have an illustration of what I mean.  Imagine we have:</p>
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;border-bottom-style: solid;"><b>MyEntity.java</b></div><div class="codeContent panelContent">
<pre class="code-java">@Entity
<span class="code-keyword">public</span> class MyEntity {
    @Id
    <span class="code-keyword">private</span> <span class="code-object">Long</span> id;
    <span class="code-keyword">private</span> <span class="code-object">String</span> name;
    <span class="code-keyword">private</span> <span class="code-object">int</span> length;
    <span class="code-keyword">private</span> Date conception;

    <span class="code-keyword">public</span> void introduceYourself(Channel channel) {
        channel.sendMessage( <span class="code-quote">"Hello, my name is %s.  I was conceived on %s"</span>, name, conception );
    }
}
</pre>
</div></div>

<p>We enhance that to:</p>
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;border-bottom-style: solid;"><b>MyEntity.java - Enhanced</b></div><div class="codeContent panelContent">
<pre class="code-java">@Entity
<span class="code-keyword">public</span> class MyEntity <span class="code-keyword">implements</span> ManagedEntity {
    @Id
    <span class="code-keyword">private</span> <span class="code-object">Long</span> id;
    <span class="code-keyword">private</span> <span class="code-object">String</span> name;
    <span class="code-keyword">private</span> <span class="code-object">int</span> length;
    <span class="code-keyword">private</span> Date conception;

    <span class="code-comment">// generated reader and writer methods <span class="code-keyword">for</span> the persistent fields above....
</span>    <span class="code-keyword">private</span> <span class="code-object">Long</span> hibernate_read_id() {
        <span class="code-keyword">if</span> ( $$_hibernate_getInterceptor() != <span class="code-keyword">null</span> ) {
            <span class="code-keyword">this</span>.id = (<span class="code-object">Long</span>) $$_hibernate_getInterceptor().readObject( <span class="code-keyword">this</span>, <span class="code-quote">"id"</span>, <span class="code-keyword">this</span>.id );
        }
        <span class="code-keyword">return</span> id;
    }

    <span class="code-keyword">private</span> void hibernate_write_id(<span class="code-object">Long</span> id) {
        <span class="code-object">Long</span> localVar = id;
        <span class="code-keyword">if</span> ( $$_hibernate_getInterceptor() != <span class="code-keyword">null</span> ) {
            localVar = (<span class="code-object">Long</span>) $$_hibernate_getInterceptor().writeObject( <span class="code-keyword">this</span>, <span class="code-quote">"id"</span>, <span class="code-keyword">this</span>.id, id );
        }
        <span class="code-keyword">this</span>.id = localVar;
    }

    <span class="code-keyword">private</span> <span class="code-object">String</span> hibernate_read_name() {
        <span class="code-keyword">if</span> ( $$_hibernate_getInterceptor() != <span class="code-keyword">null</span> ) {
            <span class="code-keyword">this</span>.name = (<span class="code-object">String</span>) $$_hibernate_getInterceptor().readObject( <span class="code-keyword">this</span>, <span class="code-quote">"name"</span>, <span class="code-keyword">this</span>.name );
        }
        <span class="code-keyword">return</span> name;
    }

    <span class="code-keyword">private</span> void hibernate_write_name(<span class="code-object">String</span> name) {
        <span class="code-object">String</span> localName = name;
        <span class="code-keyword">if</span> ( $$_hibernate_getInterceptor() != <span class="code-keyword">null</span> ) {
            localName = (<span class="code-object">String</span>) $$_hibernate_getInterceptor().writeObject( <span class="code-keyword">this</span>, <span class="code-quote">"name"</span>, <span class="code-keyword">this</span>.name, name );
        }
        <span class="code-keyword">this</span>.name = localName;
    }
    ...

    <span class="code-comment">// here you see we convert all field usages to getter/setter calls...
</span>
    <span class="code-keyword">public</span> void introduceYourself(Channel channel) {
        channel.sendMessage( <span class="code-quote">"Hello, my name is %s.  I was conceived on %s"</span>, hibernate_read_name(), hibernate_read_conception() );
    }

    <span class="code-comment">// ManagedEntity stuff
</span>    ...
}
</pre>
</div></div>

<p>All that ^^ happens today.</p>

<p>So what I was saying was that we need to hook your dirtiness tracking into those writer calls.  Unless that already is in there and I just missed it.  Something like:</p>
<div class="code panel" style="border-style: solid;border-width: 1px;"><div class="codeHeader panelHeader" style="border-bottom-width: 1px;border-bottom-style: solid;"><b>MyEntity.java - Enhanced #2</b></div><div class="codeContent panelContent">
<pre class="code-java">@Entity
<span class="code-keyword">public</span> class MyEntity <span class="code-keyword">implements</span> ManagedEntity {
    ...
    <span class="code-keyword">private</span> void hibernate_write_name(<span class="code-object">String</span> name) {
        <span class="code-object">String</span> localName = name;
        <span class="code-keyword">if</span> ( $$_hibernate_getInterceptor() != <span class="code-keyword">null</span> ) {
            localName = (<span class="code-object">String</span>) $$_hibernate_getInterceptor().writeObject( <span class="code-keyword">this</span>, <span class="code-quote">"name"</span>, <span class="code-keyword">this</span>.name, name );
        }
<span class="code-comment">// THIS !!!
</span>        $$_hibernate_trackChange( <span class="code-quote">"name"</span>, <span class="code-keyword">this</span>.name, localName );
        <span class="code-keyword">this</span>.name = localName;
    }

    @Transient
    <span class="code-keyword">private</span> HashSet&lt;<span class="code-object">String</span>&gt; dirtyAttributeNames;

    <span class="code-keyword">private</span> void $$_hibernate_trackChange(<span class="code-object">String</span> attributeName, <span class="code-object">Object</span> currentValue, <span class="code-object">Object</span> newValue) {
        <span class="code-comment">// be sure to see discussion about change testing above, but something like <span class="code-keyword">this</span>:
</span>        <span class="code-keyword">if</span> ( !areEqual( currentValue, newValue ) {
            <span class="code-keyword">if</span> ( dirtyAttributeNames == <span class="code-keyword">null</span> ) {
                dirtyAttributeNames = <span class="code-keyword">new</span> HashSet&lt;<span class="code-object">String</span>&gt;();
            }
            dirtyAttributeNames.add( attributeName );
        }
    }
}
</pre>
</div></div>


<p>Btw...  <tt>org.hibernate.test.bytecode.enhancement.SampleEntity</tt> is a sample entity that implements all these things directly.  It helps me better visualize the enhanced class.  As you can see in there, we already have an interceptor (<tt>org.hibernate.engine.spi.PersistentAttributeInterceptor</tt>) in place, but that is meant to call outside the entity back into the Session (to potentially load state for example).</p>

<hr />

<blockquote>
<p>another thing (and this is from not knowing anything about how its currently handled), but couldnt this also be used to find the fields needed when doing dynamic updates etc? perhaps we could create some logic in bytecode to handle that as well? </p></blockquote>

<p>We just need to know which attributes changed to properly handle dynamic updates.  So yes that could be handled from this <tt>InLineDirtyCheckable</tt> (temporary name) feature.  It is very similar in regards to finding dirty fields as we see in <tt>org.hibernate.CustomEntityDirtinessStrategy</tt> as discussed in the blog.  The trouble is how we can convert a set of the names of the attributes which are dirty into an array of the indexes (relative to internal Hibernate data structures) of the attributes that are dirty :/  That is the purpose of the <tt>org.hibernate.CustomEntityDirtinessStrategy#findDirty</tt> method.  We'd have to decide how to best handle that here.</p></div>
        <div style="color:#505050;padding:4px 0 0 0;">                </div>
    </td>
</tr>
                    </table>
                </td>
            </tr>
        </table>
    </td>
</tr>













            </table>
        </td><!-- End #email-page -->
    </tr>
    <tr valign="top">
        <td style="color:#505050;font-family:Arial,FreeSans,Helvetica,sans-serif;font-size:10px;line-height:14px;padding: 0 16px 16px 16px;text-align:center;">
            This message is automatically generated by JIRA.<br />
            If you think it was sent incorrectly, please contact your JIRA administrators<br />
            For more information on JIRA, see: <a style='color:#6c797f;' href='http://www.atlassian.com/software/jira'>http://www.atlassian.com/software/jira</a>
        </td>
    </tr>
</table><!-- End #email-wrap -->
</div><!-- End #email-body -->