2010-06-01 67 views
3

我JPA實體的類層次結構,所有從BaseEntity類繼承:JPA entitylisteners和@Embeddable

@MappedSuperclass 
@EntityListeners({ ValidatorListener.class }) 
public abstract class BaseEntity implements Serializable { 
    // other stuff 
} 

我想驗證實現給定的接口的所有實體自動對堅持和/或更新。這是我得到的。

我ValidatorListener:

public class ValidatorListener { 

    private enum Type { 
     PERSIST, UPDATE 
    } 

    @PrePersist 
    public void checkPersist(final Object entity) { 
     if (entity instanceof Validateable) { 
      this.check((Validateable) entity, Type.PERSIST); 
     } 
    } 

    @PreUpdate 
    public void checkUpdate(final Object entity) { 
     if (entity instanceof Validateable) { 
      this.check((Validateable) entity, Type.UPDATE); 
     } 
    } 

    private void check(final Validateable entity, final Type persist) { 
     switch (persist) { 
     case PERSIST: 
      if (entity instanceof Persist) { 
       ((Persist) entity).persist(); 
      } 
      if (entity instanceof PersistOrUpdate) { 
       ((PersistOrUpdate) entity).persistOrUpdate(); 
      } 
      break; 
     case UPDATE: 
      if (entity instanceof Update) { 
       ((Update) entity).update(); 
      } 
      if (entity instanceof PersistOrUpdate) { 
       ((PersistOrUpdate) entity).persistOrUpdate(); 
      } 
      break; 

     default: 
      break; 
     } 
    } 

} 

,這裏是我的Validateable接口,它會針對(外部接口僅僅是一個標誌,內包含的方法):

public interface Validateable { 

    interface Persist extends Validateable { 
     void persist(); 
    } 

    interface PersistOrUpdate extends Validateable { 
     void persistOrUpdate(); 
    } 

    interface Update extends Validateable { 
     void update(); 
    } 

} 

所有這些作品,但是我想將這種行爲擴展到Embeddable類。我知道兩個解決方案:

  1. 呼叫從實體驗證方法的嵌入對象的驗證方法手動:

    public void persistOrUpdate(){ 
        // validate my own properties first 
        // then manually validate the embeddable property: 
        myEmbeddable.persistOrUpdate(); 
        // this works but I'd like something that I don't have to call manually 
    } 
    
  2. 使用反射,檢查所有的屬性,看看他們的類型之一他們的接口類型。這會奏效,但並不漂亮。有沒有更優雅的解決方案?

+0

這是JPA 1還是2? – 2010-06-01 09:29:14

+0

方法1似乎很好,我沒有看到它有什麼問題。 – ewernli 2010-06-01 09:45:41

+0

@shervin jpa2,但我不認爲這有什麼區別,@ewernli:我想要一個自動化的解決方案,我希望它爲嵌入式工作,就像實體和mappersperperclass – 2010-06-01 09:58:56

回答

1

考慮基於註解的方法。它會產生更少的代碼(看起來),並且幾乎總是易於理解。

介紹新的註釋:

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE, ElementType.METHOD}) 
public @interface Validators { 
    String[] values(); 
} 

將此註釋應用於需要驗證每個實體和嵌入對象,例如:

@MappedSuperclass 
@EntityListeners({ ValidatorListener.class }) 
@Validators({Type.PERSIST, Type.UPDATE}) 
public abstract class MyEntity extends BaseEntity implements Serializable, Validateable { 
    // other stuff 
    @Validators(Type.PERSIST) 
    @Embedded 
    public Address getAddress() { 
     return address; 
    } 
} 

當然,每一個實體和嵌入對象應該還是實現Validateable界面變得更簡單:

public interface Validateable { 
    void validate(Type type); 
} 

然後驗證邏輯就變得簡單了:

  1. 如果檢查實體都被註解@Validators;
  2. 如果不是,則轉到遍歷嵌入的元素;
  3. 檢查實體是否執行Validateable;
  4. 如果沒有的話去遍歷嵌入式元素(可能爲發出警告的實體:「實體標記Validators但沒有實現Validatable接口」)
  5. 如果既肯定,然後運行validate如果適用類型對應於聽者;
  6. 使用與上述相同的邏輯迭代嵌入的元素。

該方法允許您從驗證邏輯(Java類 - 實體和可嵌入類)中分離對實體及其可嵌入元素(註釋)的聲明驗證。例如,有時可嵌入對象可能實現Validateable,但不需要驗證。聽衆似乎也變得更簡單了。

但是,如果你不是從驗證邏輯中分離驗證聲明後,你的解決方案是相當令人滿意的,可能更簡單。

+0

雖然我很喜歡你的解決方案,但我不打算使用它。 a)我想要驗證方法在實體類中。 b)我使用類型層次結構,並希望在我的validate()方法中使用super.validate()。我不想維護外部驗證器類(在我的驗證邏輯中,我主要檢查是否設置了必需的字段,如'type是一個數量必須是1') – 2010-06-02 04:55:38

+0

@seanizer - 驗證方法在裏面實體類 - 我很抱歉,我不明白這點。相同的接口@Validateable仍然以相同的方式應用。 – topchef 2010-06-02 11:08:06

+0

好的,但我真的不明白爲什麼我不堅持使用@PrePersist和@PreUpdate對實體中的方法進行註釋(我最初使用的方法,但我更喜歡基於接口的方法) – 2010-06-02 14:12:49

0

OK,這是我自己的解決方案:

http://pastebin.com/YPmt7ifm

我用彈簧BeanUtils的遍歷性。仍然:有人得到一個更優雅的解決方案?