2010-06-01 90 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的遍历性。仍然:有人得到一个更优雅的解决方案?