我的任務是爲自定義驗證創建註釋。這是由於handling database constraint violations nicely.的一些問題,我做了什麼迴應這是相對簡單。我爲需要它的一個域類創建了一個類級CustomConstraint。我得到了我的當前結果如下:自定義驗證註解引入ConcurrentModificationException
@UniqueLocation譯註:
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueLocationValidator.class)
@Documented
public @interface UniqueLocation {
String message() default "must be unique!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
這不是壯觀,實際上它被複制幾乎逐字從hibernate documentation.
我繼續創建我的UniqueLocationValidator
,並遇到了在那裏使用持久化上下文的問題。我想運行一個防禦選擇,因此試圖注入我的應用程序範圍廣泛的@Produces @PersistenceContext EntityManager
。
爲此我包括JBoss Seam的使用它的InjectingConstraintValidatorFactory
配置我的validation.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<validation-config
xmlns="http://jboss.org/xml/ns/javax/validation/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd">
<constraint-validator-factory>
org.jboss.seam.validation.InjectingConstraintValidatorFactory
</constraint-validator-factory>
</validation-config>
運行到一些問題,Creating Constraint Violations後,這是我的驗證實際效果的:
@ManagedBean
public class UniqueLocationValidator implements
ConstraintValidator<UniqueLocation, Location> {
// must not return a result for name-equality on the same Id
private final String QUERY_STRING = "SELECT * FROM Location WHERE locationName = :value AND id <> :id";
@Inject
EntityManager entityManager;
private String constraintViolationMessage;
@Override
public void initialize(final UniqueLocation annotation) {
constraintViolationMessage = annotation.message();
}
@Override
public boolean isValid(final Location instance,
final ConstraintValidatorContext context) {
if (instance == null) {
// Recommended, instead use explicit @NotNull Annotation for
// validating non-nullable instances
return true;
}
if (duplicateLocationExists(instance)) {
createConstraintViolations(context);
return false;
} else {
return true;
}
}
private void createConstraintViolations(
final ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(constraintViolationMessage)
.addNode("locationName").addConstraintViolation();
}
private boolean duplicateLocationExists(final Location location) {
final String checkedValue = location.getLocationName();
final long id = location.getId();
Query defensiveSelect = entityManager.createNativeQuery(QUERY_STRING)
.setParameter("value", checkedValue).setParameter("id", id);
return !defensiveSelect.getResultList().isEmpty();
}
}
對於我目前的配置,現在到了真正的牛肉,這個問題:
當我運行下面的代碼後r從用戶那裏獲取一個動作,這個東西奇妙而正確地將一個重複的位置名稱標記爲無效。當位置名稱不重複時,持久化工作也很好。
public long add(@Valid final Location location) {
entityManager.persist(location);
return location.getId();
}
記住,這裏的entityManager
和entityManager
在UniqueLocationValidator都通過焊接CDI注入從上述@PersistenceContext EntityManager的。
什麼不工作如下:
public long update(@Valid final Location location){
entityManager.merge(location);
return location.getId();
}
調用此代碼,我得到一個相對較短的堆棧跟蹤,具有ConcurrentModificationException
的根源。
我既不明白爲什麼會這樣,也不知道如何解決這個問題。我沒有試圖明確地多線程化我的應用程序,所以這應該由我作爲應用程序服務器使用的JBoss 7.1.1-Final來管理。