3

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

4

2 回答 2

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. if both yes, then run validate if applicable type corresponds to listener;
  6. iterate over embedded elements with the same logic as above.

This approach allows you to separate declaring validation on entities and its embeddable elements (annotations) from validation logic (Java classes - entities and embeddable classes). For example, sometimes embeddable object may implement Validateable but no validation is required. It seems that listener also becomes simpler.

But if you are not after separating validation declarations from validation logic then your solution is quite satisfactory and possibly simpler.

于 2010-06-01T19:17:30.617 回答
0

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

http://pastebin.com/YPmt7ifm

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

于 2010-06-01T10:18:58.333 回答