JPA entitylisteners和@embeddable

时间:2010-06-01 09:28:30

标签: java orm jpa jpa-2.0 entitylisteners

我有一个JPA实体的类层次结构,它们都继承自BaseEntity类:

@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. 使用反射,检查所有属性以查看其类型是否属于其中一种接口类型。这可行,但它不漂亮。有更优雅的解决方案吗?

2 个答案:

答案 0 :(得分: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. 如果没有,则继续迭代嵌入元素;
  4. 检查实体是否实现Validateable;
  5. 如果没有则继续迭代嵌入元素(可能会发出实体警告:'标有Validators但未实现Validatable接口的实体')
  6. 如果两者都是,则运行validate如果适用的类型对应于监听器;
  7. 使用与上面相同的逻辑迭代嵌入式元素。
  8. 此方法允许您将实体及其可嵌入元素(注释)的声明验证与验证逻辑(Java类 - 实体和可嵌入类)分开。例如,有时可嵌入对象可能会实现Validateable,但不需要验证。听众似乎也变得更简单了。

    但是如果你没有将验证声明与验证逻辑分开,那么你的解决方案非常令人满意并且可能更简单。

答案 1 :(得分:0)

好的,这是我自己的解决方案:

http://pastebin.com/YPmt7ifm

我正在使用spring BeanUtils迭代属性。仍然:有人有更优雅的解决方案吗?