2011-08-23 26 views
5

Estoy migrando una aplicación de configuración hibernate xml a anotaciones, no estoy seguro de cómo adaptar mi clase BusinessObjectInterceptor al nuevo formato basado en anotaciones.Interceptores Hibernate con anotaciones

Estamos cambiando nuestra clase HibernateUtil desde la creación de SessionFactory

  InitialContext ctx  = new InitialContext(); 
     sessionFactory = (SessionFactory)ctx.lookup("java:/hibernate/SessionFactory"); 

a la creación de EntityManagerFactory

  entityManagerFactory = Persistence.createEntityManagerFactory("primary"); 

Estamos cambiando nuestra clase HibernateUtil el uso de sessionFactory.openSession() para crear una sesión de un EntityManager

  //s = sessionFactory.openSession(new BusinessObjectInterceptor()); 
     EntityManager entityManager = entityManagerFactory.createEntityManager(); 
     s = entityManager.unwrap(Session.class); 

El problema que s No estoy seguro de cómo inyectar un BusinessObjectInterceptor en una nueva sesión de Hibernate, o la forma correcta de anotar mis clases para que puedan usar el Interceptor

Estoy tratando de configurar el Interceptor como una propiedad en persistencia. xml. No estoy seguro de si esto es correcto

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.0" 
xmlns="http://java.sun.com/xml/ns/persistence" 

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation=" 
    http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="primary"><jta-data-source>java:jboss/datasources/MySqlDS</jta-data-source> 

    <properties> 
    <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> 
    <property name="hibernate.ejb.interceptor.session_scoped" value="com.mycompany.common.persistence.BusinessObjectInterceptor"/> 
      </properties> 

Nuestras clases se han configurado previamente a través de archivos hbm.xml

<?xml version="1.0"?> 
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping> 
    <class name="com.mycompany.liveexpert.common.businessobjects.ServerSettings" table="server_settings"> 
      <id name="serverSettingsID" type="integer" column="server_settings_id"> 
        <generator class="identity" /> 
      </id> 
      <version name="updateCounter" column="update_counter"/> 
      <property name="changedDate" type="timestamp" column="changed_date"/> 
      <property name="changedBy" type="string" column="changed_by"/> 
      <property name="createdDate" type="timestamp" column="created_date"/> 
      <property name="createdBy" type="string" column="created_by"/> 
      <property name="status" type="string" column="status"/> 

      <property name="emailServer" type="string" column="email_server" /> 
      <property name="emailFromAddress" type="string" column="email_from_address" /> 
      <property name="emailUser" type="string" column="email_user" /> 
      <property name="emailPassword" type="string" column="email_password" /> 

</class> 

las clases anotadas parecen

@Entity 
@Table(name="server_settings") 
public class ServerSettings extends BusinessObject 
{ 
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Integer serverSettingsID; 
    @Column(name = "email_server") 
    private String emailServer; 
    @Column(name = "email_from_address") 
private String emailFromAddress; 
    @Column(name = "email_user") 
private String emailUser; 
    @Column(name = "email_password") 
private String emailPassword; 

Tenemos una clase BusinessObjectInterceptor y una clase BusinessObject. Los publicaré a continuación como referencia. Creo que lo que debe suceder es que la clase BusinessObject necesite ser anotada, no estoy seguro de cómo se hace, ya que BusinessObject no se correlaciona con columnas en una tabla específica, sino más bien con columnas que son comunes a todas las tablas en nuestra base de datos. Pegaré estas dos clases a continuación. Cualquier consejo sobre cómo configurar mi Interceptor con anotaciones sería apreciado. Gracias.

BusinessObjectInterceptor

public class BusinessObjectInterceptor extends EmptyInterceptor 
{ 
private int updates; 
private int creates; 

private static final String defaultDesignation = "system"; 

private String getUserDesignation() 
{ 
    UserContextI theContext = PersistenceContext.getUserContext(); 
    if (theContext == null) return defaultDesignation; 
    String uid = theContext.getUserDesignation(); 
    if (uid == null) return defaultDesignation; 
    return uid; 
} 
public boolean onFlushDirty(Object entity, 
          Serializable id, 
          Object[] currentState, 
          Object[] previousState, 
          String[] propertyNames, 
          Type[] types) 
{ 
    boolean theReturn = false; 
    if (entity instanceof BusinessObject) 
    { 
     updates++; 
     for (int i=0; i<propertyNames.length; i++) 
     { 
      if ("changedDate".equals(propertyNames[i])) 
      { 
       currentState[i] = new Date(); 
       theReturn = true; 
      } 
      if ("changedBy".equals(propertyNames[i])) 
      { 
       currentState[i] = getUserDesignation(); 
       theReturn = true; 
      } 
     } 
    } 
    return theReturn; 
} 
public boolean onSave(Object entity, 
     Serializable id, 
     Object[] state, 
     String[] propertyNames, 
     Type[] types) 
{ 
    boolean theReturn = false; 
    if (entity instanceof BusinessObject) 
    { 
     creates++; 
     for (int i=0; i<propertyNames.length; i++) 
     { 
      if ("createdDate".equals(propertyNames[i])) 
      { 
       state[i] = new Date(); 
       theReturn = true; 
      } 
      if ("createdBy".equals(propertyNames[i])) 
      { 
       state[i] = getUserDesignation(); 
       theReturn = true; 
      } 
      if ("changedDate".equals(propertyNames[i])) 
      { 
       state[i] = new Date(); 
       theReturn = true; 
      } 
      if ("changedBy".equals(propertyNames[i])) 
      { 
       state[i] = getUserDesignation(); 
       theReturn = true; 
      } 
     } 
    } 
    return theReturn; 
} 
public void preFlush(Iterator entities) 
{ 
    updates = 0; 
    creates = 0; 
} 

BusinessObject

public abstract class BusinessObject 
{ 
private String status; 
private String createdBy; 
private Date createdDate; 
private String changedBy; 
private Date changedDate; 
private int updateCounter; 

/** 
* Generic save method to be used for persisting a business object. 
* 
* @return a copy of this business object in its saved state. 
* 
* @throws Exception 
*/ 
public BusinessObject save() throws Exception 
{ 
    Session  hsession = null; 
    Transaction tx = null; 
    BusinessObject theObject = null; 

    validate(); // throws ValidationException 

    try { 
     hsession = HibernateUtil.currentSession(); 
     tx = hsession.beginTransaction(); 

     if (getStatus() == null || getStatus().length() < 1) 
     { 
      setStatus("OK"); 
     } 

     //theObject = (BusinessObject) hsession.saveOrUpdateCopy(this); 
     theObject = (BusinessObject) hsession.merge(this); 
     if (tx != null && tx.isActive() && !tx.wasCommitted()) 
      tx.commit(); 
    } catch (Exception e){ 
     try 
     { 
     if (tx!=null) tx.rollback(); 
     } catch (Exception e3) 
     {} 
     try 
     { 
     hsession.close(); 
     } catch (Exception e2) 
     {} 
     throw e; 
    } finally 
    { 
     HibernateUtil.closeSession(); 
    } 
    return theObject; 
} 
+0

posible duplicado de anotaciones [uso de la primavera para aplicar automáticamente Hibernate Interceptor?] (http://stackoverflow.com/questions/2132151/use-spring-annotations-to-automatically-apply-hibernate-interceptor) –

+0

podría ser alguna información en eso q Pregunta que me puede ayudar, pero no estoy usando Spring, así que no es del todo aplicable. – user619804

+0

Ok.No puedo retractarme de mi voto cercano, pero si se cierra, votaré para volver a citar. –

Respuesta

2

En JPA puede utilizar @PrePersist@PreUpdate y anotación para anotar un método en su modelo (clase @Entity) que será llamada antes de que persiste (INSERT) o actualización (UPDATE).

Puede crear un detector de entidad, y añadir @EntityListeners anotación a sus modelos, como:

public class BusinessListener { 
    @PrePersist 
    public void businessUpdate(BusinessObject obj) { 
     obj.setCreatedDate(new Date()); 
     .... 
    } 
    @PreUpdate 
    public void businessUpdate(BusinessObject obj) { 
     obj.setChangedDate(new Date()); 
     .... 
    } 
} 

@EntityListeners(class=...BusinessListener) 
public class BusinessObject { 
} 

O usted podría poner métodos en una clase de entidad de base y se extienden a todas sus entidades de ella, como:

public class BusinessObject { 
    @PrePersist 
    public void businessUpdate() { 
     createdDate = new Date(); 
     .... 
    } 
    @PreUpdate 
    public void businessUpdate() { 
     changedDate = new Date(); 
     .... 
    } 
} 
+1

Eso no es exactamente lo mismo. Es decir. en 'EmptyInterceptor # onDirtyFlush' puede pasar el estado de la entidad anterior/actual. Pero '@ PreUpdate' o' @ EntityListener' podrían decirle solo el estado actual. Quiero decir que los interceptores son aún más poderosos que sus amigos anotados –

Cuestiones relacionadas