【问题标题】:JPA entitylisteners and @embeddableJPA 实体监听器和@embeddable
【发布时间】:2010-06-01 09:28:29
【问题描述】:

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

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

我希望所有实现给定接口的实体在持久化和/或更新时自动得到验证。这就是我所拥有的。

我的验证器监听器:

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. 使用反射,检查所有属性以查看它们的类型是否属于它们的接口类型之一。这会起作用,但它并不漂亮。有没有更优雅的解决方案?

【问题讨论】:

  • 方法 1 看起来不错,我看不出它有什么问题。
  • @shervin jpa2,但我不认为这有什么不同,@ewernli:我想要一个自动化的解决方案,我希望它能像实体和映射器超类一样适用于可嵌入对象
  • 以防万一,我会添加jpa2标签

标签: java orm jpa jpa-2.0 entitylisteners


【解决方案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,但不需要验证。听者似乎也变得更简单了。

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

【讨论】:

  • 虽然我在某种程度上喜欢您的解决方案,但我不会使用它。 a)我希望验证方法位于实体类中。 b) 我使用类型层次结构并希望在我的 validate() 方法中使用 super.validate()。我不想维护外部验证器类(在我的验证逻辑中,我主要检查是否设置了必填字段以及诸如“如果类型为 a 那么数量必须为 1”之类的内容)
  • @seanizer - 验证方法在实体类中 - 很抱歉,不知何故我不清楚这一点。相同的接口@Validateable 仍然以相同的方式应用。
  • 好的,但是我真的不明白为什么我不只是在实体中的方法上坚持使用@PrePersist 和@PreUpdate 注释(我最初使用的一种方法,但我更喜欢界面基于方法)
  • 刚刚编辑了 lat 段落,因为我相信它回答了这个问题。我认为您的解决方案完全可以。
  • 谢谢。我会接受你的回答,因为它很好,虽然我不会使用它:-)
【解决方案2】:

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

http://pastebin.com/YPmt7ifm

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

【讨论】:

    猜你喜欢
    • 2012-07-25
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    相关资源
    最近更新 更多