Steve Ebersole commented on Technical task HHH-8354

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.

This is all within Enhancer. I think maybe its good to have an illustration of what I mean. Imagine we have:

MyEntity.java
@Entity
public class MyEntity {
    @Id
    private Long id;
    private String name;
    private int length;
    private Date conception;

    public void introduceYourself(Channel channel) {
        channel.sendMessage( "Hello, my name is %s.  I was conceived on %s", name, conception );
    }
}

We enhance that to:

MyEntity.java - Enhanced
@Entity
public class MyEntity implements ManagedEntity {
    @Id
    private Long id;
    private String name;
    private int length;
    private Date conception;

    // generated reader and writer methods for the persistent fields above....
    private Long hibernate_read_id() {
        if ( $$_hibernate_getInterceptor() != null ) {
            this.id = (Long) $$_hibernate_getInterceptor().readObject( this, "id", this.id );
        }
        return id;
    }

    private void hibernate_write_id(Long id) {
        Long localVar = id;
        if ( $$_hibernate_getInterceptor() != null ) {
            localVar = (Long) $$_hibernate_getInterceptor().writeObject( this, "id", this.id, id );
        }
        this.id = localVar;
    }

    private String hibernate_read_name() {
        if ( $$_hibernate_getInterceptor() != null ) {
            this.name = (String) $$_hibernate_getInterceptor().readObject( this, "name", this.name );
        }
        return name;
    }

    private void hibernate_write_name(String name) {
        String localName = name;
        if ( $$_hibernate_getInterceptor() != null ) {
            localName = (String) $$_hibernate_getInterceptor().writeObject( this, "name", this.name, name );
        }
        this.name = localName;
    }
    ...

    // here you see we convert all field usages to getter/setter calls...

    public void introduceYourself(Channel channel) {
        channel.sendMessage( "Hello, my name is %s.  I was conceived on %s", hibernate_read_name(), hibernate_read_conception() );
    }

    // ManagedEntity stuff
    ...
}

All that ^^ happens today.

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:

MyEntity.java - Enhanced #2
@Entity
public class MyEntity implements ManagedEntity {
    ...
    private void hibernate_write_name(String name) {
        String localName = name;
        if ( $$_hibernate_getInterceptor() != null ) {
            localName = (String) $$_hibernate_getInterceptor().writeObject( this, "name", this.name, name );
        }
// THIS !!!
        $$_hibernate_trackChange( "name", this.name, localName );
        this.name = localName;
    }

    @Transient
    private HashSet<String> dirtyAttributeNames;

    private void $$_hibernate_trackChange(String attributeName, Object currentValue, Object newValue) {
        // be sure to see discussion about change testing above, but something like this:
        if ( !areEqual( currentValue, newValue ) {
            if ( dirtyAttributeNames == null ) {
                dirtyAttributeNames = new HashSet<String>();
            }
            dirtyAttributeNames.add( attributeName );
        }
    }
}

Btw... org.hibernate.test.bytecode.enhancement.SampleEntity 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 (org.hibernate.engine.spi.PersistentAttributeInterceptor) in place, but that is meant to call outside the entity back into the Session (to potentially load state for example).


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?

We just need to know which attributes changed to properly handle dynamic updates. So yes that could be handled from this InLineDirtyCheckable (temporary name) feature. It is very similar in regards to finding dirty fields as we see in org.hibernate.CustomEntityDirtinessStrategy 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 org.hibernate.CustomEntityDirtinessStrategy#findDirty method. We'd have to decide how to best handle that here.

This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira