Как перехватывать и обертывать исключения, выдаваемые JTA при фиксации контейнера -управляемого -tx EJB?

Я борюсь с проблемой класса EJB3, который управляет нетривиальной моделью данных -. У меня возникают исключения проверки ограничений, когда мой контейнер -управляет транзакционными методами фиксации. Я хочу, чтобы они не были обернуты в EJBException, вместо этого выбрасывая разумное исключение приложения, которое могут обработать вызывающие.

Чтобы обернуть его в подходящее исключение приложения, я должен уметь его перехватывать.Большую часть времени простая попытка/поймать делает работу, потому что исключение проверки выдается из вызова EntityManager, который я сделал.

К сожалению, некоторые ограничения проверяются только во время фиксации. Например, нарушение @Size(min=1)в сопоставленной коллекции обнаруживается только тогда, когда транзакция, управляемая контейнером, фиксируется, как только она покидает мой контроль в конце моего транзакционного метода. Я не могу поймать исключение, возникающее при сбое проверки, и обернуть его, поэтому контейнер оборачивает его в javax.transaction.RollbackExceptionи оборачивает этот в проклятый EJBException. Вызывающий должен перехватить все EJBExceptions и погрузиться в цепочку причин, чтобы попытаться выяснить, не является ли это проблемой проверки, что действительно нехорошо.

Я работаю с транзакциями, управляемыми контейнером, поэтому мой EJB выглядит так:

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER
class TheEJB {

    @Inject private EntityManager em;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public methodOfInterest() throws AppValidationException {
       try {
           // For demonstration's 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. совершает.

Помощь?


Уже пробовал:

Транзакции, управляемые компонентом , решили бы мою проблему, позволив мне инициировать фиксацию в коде, которым я управляю. К сожалению, они не подходят, поскольку транзакции, управляемые компонентом, не предлагают никакого эквивалентаTransactionAttributeType.REQUIRES_NEW-невозможно приостановить транзакцию с использованием BMT. Одна из досадных оплошностей JTA.

См.:

... но смотрите ответы на предостережения и подробности.

javax.validation.ValidationExceptionявляется исключением JDK; Я не могу изменить его, чтобы добавить аннотацию @ApplicationExceptionдля предотвращения переноса. Я не могу создать подкласс, чтобы добавить аннотацию; это вызвано EclpiseLink, а не моим кодом.Я не уверен, что пометка @ApplicationExceptionв любом случае помешает Арджуне (JTA-импл )AS7 обернуть его в 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 из БД и взаимоблокировки или откаты сбоев сериализации с помощью SQLSTATE 40P01. и 40001 соответственно . Вот почему подход, который просто пытается убедиться, что коммит никогда не сработает, не сработает. Исключения проверенных приложений не могут быть выброшены через фиксацию JTA, потому что интерфейсы JTA, естественно, не объявляют их, но непроверенные @ApplicationExceptionаннотированные исключения должны быть в состоянии.

Кажется, что везде, где я могу с пользой перехватить исключение приложения, я также могу -хотя и менее красиво -перехватить EJBException и углубиться в него в поисках исключения JTA и базовой проверки или исключения JDBC, а затем принять решение на основе этого. Без функции фильтрации исключений в JTA мне, вероятно, придется.

21
задан Craig Ringer 6 August 2012 в 04:37
поделиться