JPA entitylisteners和@Embeddable
我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类。我知道两个解决方案:
-
呼叫从实体验证方法的嵌入对象的验证方法手动:
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 }
使用反射,检查所有的属性,看看他们的类型之一他们的接口类型。这会奏效,但并不漂亮。有没有更优雅的解决方案?
考虑基于注解的方法。它会产生更少的代码(看起来),并且几乎总是易于理解。
介绍新的注释:
@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);
}
然后验证逻辑就变得简单了:
- 如果检查实体都被注解
@Validators
; - 如果不是,则转到遍历嵌入的元素;
- 检查实体是否执行
Validateable
; - 如果没有的话去遍历嵌入式元素(可能为发出警告的实体:“实体标记
Validators
但没有实现Validatable
接口”) - 如果既肯定,然后运行
validate
如果适用类型对应于听者; - 使用与上述相同的逻辑迭代嵌入的元素。
该方法允许您从验证逻辑(Java类 - 实体和可嵌入类)中分离对实体及其可嵌入元素(注释)的声明验证。例如,有时可嵌入对象可能实现Validateable
,但不需要验证。听众似乎也变得更简单了。
但是,如果你不是从验证逻辑中分离验证声明后,你的解决方案是相当令人满意的,可能更简单。
虽然我很喜欢你的解决方案,但我不打算使用它。 a)我想要验证方法在实体类中。 b)我使用类型层次结构,并希望在我的validate()方法中使用super.validate()。我不想维护外部验证器类(在我的验证逻辑中,我主要检查是否设置了必需的字段,如'type是一个数量必须是1') – 2010-06-02 04:55:38
@seanizer - 验证方法在里面实体类 - 我很抱歉,我不明白这点。相同的接口@Validateable仍然以相同的方式应用。 – topchef 2010-06-02 11:08:06
好的,但我真的不明白为什么我不坚持使用@PrePersist和@PreUpdate对实体中的方法进行注释(我最初使用的方法,但我更喜欢基于接口的方法) – 2010-06-02 14:12:49
这是JPA 1还是2? – 2010-06-01 09:29:14
方法1似乎很好,我没有看到它有什么问题。 – ewernli 2010-06-01 09:45:41
@shervin jpa2,但我不认为这有什么区别,@ewernli:我想要一个自动化的解决方案,我希望它为嵌入式工作,就像实体和mappersperperclass – 2010-06-01 09:58:56