Я боюсь проблемы с классом EJB3, который управляет нетривиальной моделью данных. У меня есть исключения проверки проверки ограничений, которые вызывают, когда мои транзакционные методы, управляемые контейнером, совершают. Я хочу, чтобы они не были обернуты в EJBException
, вместо этого бросая разумное исключение приложения, которое могут обрабатывать вызывающие.
Чтобы обернуть его в подходящее исключение приложения, я должен уметь его поймать. В большинстве случаев простой try/catch выполняет задание, потому что исключение проверки исключается из вызова EntityManager
, который я сделал.
К сожалению, некоторые ограничения проверяются только в момент фиксации. Например, нарушение @Size(min=1)
в сопоставленной коллекции происходит только тогда, когда транзакция, управляемая контейнером, совершает транзакцию, когда она покидает мой контроль в конце моего транзакционного метода. Я не могу уловить исключение, возникшее при завершении проверки и его завершении, поэтому контейнер обертывает его в javax.transaction.RollbackException
и обертывает в проклятом EJBException
. Вызывающий должен поймать все EJBException
и пойти в дайвинг в цепочке причин, чтобы попытаться выяснить, есть ли проблема проверки, что действительно не приятно.
Я работаю с транзакциями, управляемыми контейнерами, поэтому мой EJB выглядит так:
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER
class TheEJB {
@Inject private EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public methodOfInterest() throws AppValidationException {
try {
// For demonstration sake create a situation that'll cause validation to
// fail at commit-time here, like
someEntity.getCollectionWithMinSize1().removeAll();
em.merge(someEntity);
} catch (ValidationException ex) {
// Won't catch violations of @Size on collections or other
// commit-time only validation exceptions
throw new AppValidationException(ex);
}
}
}
... где AppValidationException
- проверенное исключение или неконтролируемое исключение, аннотированное @ApplicationException
, поэтому оно не обернуто EJB3.
Иногда я могу вызвать раннее нарушение ограничений с помощью EntityManager.flush()
и поймать это, но не всегда. Даже тогда я действительно хотел бы уловить нарушения ограничений на уровне базы данных, вызванные проверками с задержкой на ограничение времени фиксации, и они будут возникать только тогда, когда JTA совершит.
Справка
Уже пробовали:
Bean управляемые транзакции решают мою проблему, позволяя мне инициировать фиксацию в коде, которым я управляю. К сожалению, они не являются опцией, поскольку управляемые транзакции bean не предлагают никакого эквивалента TransactionAttributeType.REQUIRES_NEW
- нет способа приостановить транзакцию с использованием BMT. Один из раздражающих оплошностей JTA.
Смотрите:
- Почему нам нужна JTA 2.0
- Bean -Управляемая транзакционная приостановка в J2EE (не делайте этого!)
... но см. ответы на предостережения и подробности.
javax.validation.ValidationException
- исключение JDK; Я не могу изменить его, чтобы добавить an @ApplicationException
аннотацию, чтобы предотвратить упаковку. Я не могу подклассифицировать его, чтобы добавить аннотацию; он был выброшен EclpiseLink, а не мой код. Я не уверен, что его отметка @ApplicationException
остановит Arjuna (AS7 JTA impl), завернув ее в RollbackException
.
Я попытался использовать EJB3-перехватчик следующим образом:
@AroundInvoke
protected Object exceptionFilter(InvocationContext ctx) throws Exception {
try {
return ctx.proceed();
} catch (ValidationException ex) {
throw new SomeAppException(ex);
}
}
... но кажется, что перехватчики срабатывают внутри JTA (что разумно и обычно желательно), поэтому исключение, которое я хочу поймать, еще не было выброшено.
Я предполагаю, что я хочу, чтобы иметь возможность определять фильтр исключений, который применял после, JTA делает свою вещь. Любые идеи?
Я работаю с JBoss AS 7.1.1.Final и EclipseLink 2.4.0. EclipseLink устанавливается как модуль JBoss в соответствии с этими инструкциями, но это не имеет большого значения для данной проблемы.
ОБНОВЛЕНИЕ:. После того, как мы подумали над этой проблемой, я понял, что в дополнение к исключениям проверки JSR330 мне действительно нужно уметь ловить SQLIntegrityConstraintViolationException из DB и откаты блокировки или сериализации с помощью SQLSTATE 40P01 и 40001 соответственно. Поэтому подход, который просто пытается убедиться, что фиксация никогда не будет брошена, не будет работать хорошо. Проверенные исключения приложений не могут быть переданы с помощью JTA-фиксации, потому что интерфейсы JTA, естественно, не объявляют их, но неконтролируемые исключения @ApplicationException
должны быть в состоянии.
Кажется, что в любом месте, где я могу с пользой поймать исключение приложения, я могу - хотя и менее красиво - поймать исключение EJBException и углубиться в него для исключения JTA и базовой проверки или исключения JDBC, а затем принять решение на основе этого. Без функции фильтра исключений в JTA мне, вероятно, придется.