-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Interceptor.instantiate for injecting entities
PostPosted: Mon Oct 20, 2008 7:53 pm 
Newbie

Joined: Fri Oct 17, 2008 7:01 pm
Posts: 2
Location: San Francisco
Hi,

I wrote an Interceptor with an instantiate that uses a Guice injector to construct entity objects. I'm seeing Hibernate call the default constructor on the entity object anyway, so it's not always using Interceptor.instantiate to do the work.

What are these default-construct objects for? What functions might be called on the default objects? Does hibernate ever expose any of these objects as the result of a load or query?

My objects' getters/setters for the persistent properties should be safe without the injected dependencies. However, other functionality in the entities needs the injected dependencies, and I need to ensure that my end user never gets an object constructed with the default constructor.

I'm using Hibernate 3.2.6 and Annotations 3.3.1. I've included the complete source for the interceptor and a simple test that reveals my problem (see the note in the PojoInjectorTest.Pojo.Pojo()).

PojoInjector:
Code:
import com.google.inject.Injector;

import org.hibernate.CallbackException;
import org.hibernate.EmptyInterceptor;
import org.hibernate.EntityMode;
import org.hibernate.SessionFactory;

import java.io.Serializable;

class PojoInjector extends EmptyInterceptor {
 
  private Injector injector = null;
  private SessionFactory sf = null;

  /*
   * The PojoInjector requires the SessionFactory to set identifiers, but the
   * PojoInjector is required to build the SesisonFactory, so we can't inject
   * this into a constructor.
   */
  void setSessionFactory(SessionFactory sf) {
    this.sf = sf;
  }

  void setInjector(Injector injector) {
    this.injector = injector;
  }
 
  @Override
  public Object instantiate(String entityName, EntityMode entityMode, Serializable id)
      throws CallbackException {
    if (entityMode != EntityMode.POJO) {
      return super.instantiate(entityName, entityMode, id);
    }
    try {
      Class<?> clazz = PojoInjector.class.getClassLoader().loadClass(entityName);
      Object obj = injector.getInstance(clazz);
      sf.getClassMetadata(entityName).setIdentifier(obj, id, entityMode);
      return obj;
    } catch (Exception exn) {
      String msg = String.format("Could not inject %s", entityName);
      throw new CallbackException(msg, exn);
    }
  }

}


PojoInjectorTest.java
Code:
import static javax.persistence.GenerationType.AUTO;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.classextension.EasyMock.createStrictControl;

import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;

import junit.framework.TestCase;

import org.easymock.IMocksControl;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
* @author topher@google.com (Your Name Here)
*
*/
public class PojoInjectorTest extends TestCase {
 
  // Something our POJO depends on.
  public static interface Dependency {
    public void yepPojoWasInjected();
  }

  // Our POJO for an entity.
  @Entity
  public static class Pojo {
    @Id @GeneratedValue(strategy = AUTO)
    private int id;
   
    public Pojo() {
      // This gets called twice, but I expected never.
    }
   
    @Inject
    public Pojo(Dependency dep) {
      dep.yepPojoWasInjected();
    }

    public int getId() {
      return id;
    }

    public void setId(int id) {
      this.id = id;
    }

  }

  // Bind a mock to the dependency.
  private static class Module extends AbstractModule {
    private Dependency dep;
   
    private Module(Dependency dep) {
      this.dep = dep;
    }
   
    @Override
    protected void configure() {
      bind(Dependency.class).toInstance(dep);
    }
  }

  public void testLoadInjectsPojo() {
   
    /*
     * Setup
     */

    IMocksControl c = createStrictControl();
    Dependency dep = c.createMock(Dependency.class);
    dep.yepPojoWasInjected();
    expectLastCall().times(2);

    Injector injector = Guice.createInjector(new Module(dep));

    PojoInjector pojoInjector = new PojoInjector();
   
    SessionFactory sf = new AnnotationConfiguration()
        .setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver")
        .setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:pojoInjectorTest")
        .setProperty("hibernate.connection.username", "sa")
        .setProperty("hibernate.connection.password", "")
        .setProperty("hibernate.hbm2ddl.auto", "create-drop")
        .addAnnotatedClass(Pojo.class)
        .setInterceptor(pojoInjector)
        .buildSessionFactory();
    pojoInjector.setSessionFactory(sf);
    pojoInjector.setInjector(injector);
   
    /*
     * Create an entity to load later.
     */
   
    c.replay();
    Session s = sf.openSession();
    Transaction t = s.beginTransaction();
    Pojo pj = injector.getInstance(Pojo.class);
    s.save(pj);
    t.commit();
    s.close();

    int savedId = pj.getId();

    /*
     * Now load the entity.
     */

    s = sf.openSession();
    t = s.beginTransaction();
    pj = (Pojo) s.load(Pojo.class, savedId);
    assertEquals(pj.getId(), savedId);
    t.commit();
    s.close();
    c.verify();

  }
}


Top
 Profile  
 
 Post subject: Re: Interceptor.instantiate for injecting entities
PostPosted: Mon Jan 04, 2010 3:49 pm 
Newbie

Joined: Fri Oct 17, 2008 7:01 pm
Posts: 2
Location: San Francisco
In Hibernate as of v3_2_6 at org/hibernate/event/def/DefaultMergeEventListener.java:172 there appears this:

persister.instantiate ... //TODO: should this be Session.instantiate(Persister, ...)?

Yes, I think so. I suspect this line is the cause of my issue. I see this line still exists on the main trunk, though now it's line 299.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.