Pojo 通常用作模型/DTO,用于将数据插入/更新到数据库中。
它们需要经过验证(使用验证器)以确保它们仅包含用例的预期字段:
为了实现这一点,如果 Java 语言已经包含跟踪 pojo 中“修改”的机制,将会很有帮助。字段的“修改”将是:
有人可以帮助我解决这样的 setter-call 检测,并使用尽可能少的样板吗?
这里是我如何使用样板解决这个问题的示例,通过让 Pojo 扩展一个公共类:
public abstract class AbstractDTO {
private Map<String, Object> modifiedFields = new HashMap<>();
public AbstractDTO() {
}
@JsonIgnore
@XmlTransient
protected void setAt(String key, Object value) {
this.modifiedFields.put(key, value);
}
@JsonIgnore
@XmlTransient
public void resetModifiedFields() {
this.modifiedFields.clear();
}
@JsonIgnore
@XmlTransient
public Map<String, Object> getModifiedFields() {
return this.modifiedFields;
}
}
实现:
public class Product extends AbstractDTO {
private Long productId;
public Long getProductId() {
return this.productId;
}
public void setProductId(Long productId) {
this.productId = productId;
this.setAt("productId", productId);
}
这样我现在可以检查修改的字段:
boolean isModified = pojo.getModifiedFields().containsKey(field.getName());
我还找到了一种借助反射的额外方法(这有助于我的设置者只需要在父级中调用
touch()
方法:
public void touch () {
StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
StackWalker.StackFrame frame = walker.walk(frames -> {
Iterator<StackWalker.StackFrame> it = frames.iterator();
StackWalker.StackFrame a = it.next();
return it.next();
});
String methodName = frame.getMethodName();
try {
String withoutSet = methodName.substring(3);
String fieldname = Character.toLowerCase(withoutSet.charAt(0)) + withoutSet.substring(1);
Class<?> declaringClass = frame.getDeclaringClass();
Field field = frame.getDeclaringClass().getDeclaredField(fieldname);
String getterName = "get" + withoutSet;
Method getter = declaringClass.getMethod(getterName);
Object value = getter.invoke(this);
this.modifiedFields.put(field.getName(), value);
} catch (Exception e) {
throw new RuntimeException("unable to find field!");
}
}
如果有人知道如何在调用 setter 时自动(在幕后)调用此“touch()”函数,这也会有所帮助。
我认为你心里有类似Javers的想法。请注意,更改跟踪库通常要求您有权访问对象的原始版本,因此请确保保留该版本而不进行更改。