2011-08-23 5 views
5

Je migre une application de la configuration hibernate xml vers des annotations, je ne sais pas comment adapter ma classe BusinessObjectInterceptor au nouveau format basé sur les annotations.Intercepteurs Hibernate avec annotations

Nous changeons notre classe HibernateUtil de créer SessionFactory

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

à la création EntityManagerFactory

  entityManagerFactory = Persistence.createEntityManagerFactory("primary"); 

Nous changeons notre classe HibernateUtil d'utiliser sessionFactory.openSession() pour la création d'une session à partir d'un EntityManager

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

Le problème i s Je ne suis pas sûr de savoir comment injecter un BusinessObjectInterceptor dans une nouvelle Session Hibernate, ou la bonne façon d'annoter mes classes pour qu'elles puissent utiliser l'Interceptor

J'essaie de définir l'Interceptor comme une propriété dans la persistance. xml. Je ne sais pas si cela est correct

<?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> 

Nos cours ont déjà été configurés via des fichiers 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> 

les classes annotées ressemblent

@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; 

Nous avons une classe BusinessObjectInterceptor et une classe BusinessObject. Je les posterai ci-dessous pour référence. Je pense que ce qui doit arriver est que la classe BusinessObject doit être annotée, je ne sais pas comment cela se fait puisque BusinessObject ne correspond pas aux colonnes d'une table spécifique, mais plutôt aux colonnes communes à toutes les tables de notre base de données. Je vais coller ces deux classes ci-dessous. Tout conseil sur comment configurer mon Interceptor avec des annotations serait apprécié. Merci.

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

double possible de [utiliser les annotations de printemps pour appliquer automatiquement Hibernate Interceptor?] (http://stackoverflow.com/questions/2132151/use-spring-annotations-to-automatically-apply-hibernate-interceptor) –

+0

Il pourrait y avoir être une information dans ce q Cela pourrait m'aider, mais je n'utilise pas Spring, donc ce n'est pas entièrement applicable. – user619804

+0

Ok.Je ne peux pas rétracter mon vote serré, mais s'il se termine, je voterai pour repoen. –

Répondre

2

En JPA, vous pouvez utiliser l'annotation @PrePersist et @PreUpdate pour annoter une méthode dans votre modèle (classe @Entity) qui sera appelée avant la persistance (INSERT) ou mise à jour (UPDATE).

Vous pouvez créer un écouteur d'entité, et ajouter une annotation @EntityListeners à vos modèles, comme:

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 { 
} 

Ou vous pourriez mettre des méthodes dans une classe d'entités de base et d'étendre toutes vos entités de lui, comme:

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

Ce n'est pas exactement pareil. C'est à dire. dans 'EmptyInterceptor # onDirtyFlush' vous pouvez passer l'état de l'entité précédente/actuelle. Mais '@ PreUpdate' ou' @ EntityListener' pourrait vous dire seulement l'état actuel. Je veux dire que les intercepteurs sont toujours plus puissants que leurs amis annotés –

Questions connexes