Wie fangen und umbrechen Sie Exceptions, die von JTA ausgelöst werden, wenn ein Container-Managed-TX EJB festlegt?

Bin ich mit folgendem problem zu kämpfen mit einer EJB3-Klasse, verwaltet ein nicht-triviales Datenmodell. Ich habe constraint validation exceptions geworfen, wenn mein container-managed Transaktions-Methoden Begehen. Ich möchte verhindern, dass Sie sich eingewickelt in EJBException statt werfen eine vernünftige Anwendung Ausnahme von den Anrufern umgehen kann.

Wickeln Sie es in einer geeigneten Anwendung Ausnahme, ich muss in der Lage sein, es zu fangen. Die meisten der Zeit eine einfache try/catch macht den job, weil die überprüfungs-Ausnahme wird ausgelöst von einem EntityManager Anruf, den ich gemacht habe.

Leider einige Einschränkungen werden nur überprüft, bei commit. Zum Beispiel, Verletzung der @Size(min=1) auf einem zugeordneten Sammlung ist nur aktiviert, wenn das container-verwaltete Transaktion verpflichtet, sobald er die Blätter meiner Kontrolle, am Ende meiner Transaktions-Methode. Ich kann nicht fangen die Ausnahme, die ausgelöst wird, wenn die Validierung fehlschlägt und wickeln Sie es, so wird der container wickelt es in ein javax.transaction.RollbackException und umschließt dass in einen Fluch EJBException. Der Anrufer hat, um zu fangen alle EJBExceptions und Tauchen in die Ursache-Kette, um zu versuchen, um herauszufinden, ob es eine überprüfung Frage, die wirklich nicht schön.

Ich arbeite mit container-verwalteten Transaktionen, so meine EJB sieht wie folgt aus:

@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);
       }
    }

}

... wo AppValidationException ist eine checked-exception oder eine ungeprüfte Ausnahme kommentierte @ApplicationException so dass es nicht erhalten, umhüllt von EJB3.

Manchmal kann ich das auslösen eines frühen constraint-Verletzung mit einer EntityManager.flush() und zu fangen, aber nicht immer. Selbst dann, würde ich wirklich gerne in der Lage sein, um trap-Datenbank-level-constraint-Verletzungen, ausgelöst durch verzögerte Einschränkungsüberprüfung bei commit zu, und die wird nur immer entstehen, wenn JTA verpflichtet.

Helfen?


Schon versucht:

Bean-verwaltete Transaktionen würde mein problem lösen, indem Sie mich zum auslösen der commit-code I-control. Leider sind Sie keine option, da bean-verwaltete Transaktionen bieten Sie nicht äquivalent TransactionAttributeType.REQUIRES_NEW - es gibt keine Möglichkeit zum anhalten einer Transaktion mit BMT. Einer der ärgerliche Versäumnisse von JTA.

Finden Sie unter:

... aber siehe Antworten für Vorbehalte und details.

javax.validation.ValidationException ist ein JDK Ausnahme, ich kann Sie nicht ändern, um fügen Sie eine @ApplicationException annotation um zu verhindern, dass die Verpackung. Ich kann keine Unterklasse hinzufügen der annotation; geworfen von EclpiseLink, nicht mein code. Ich bin mir nicht sicher, dass es markieren @ApplicationException aufhören würde, Arjuna (AS7 - JTA-impl) wickelte Sie in ein RollbackException sowieso.

Ich habe versucht, eine EJB3-interceptor wie diese:

@AroundInvoke
protected Object exceptionFilter(InvocationContext ctx) throws Exception {
    try {
        return ctx.proceed();
    } catch (ValidationException ex) {
        throw new SomeAppException(ex);
    }
}

... aber es scheint, dass Abfangjäger Feuer innen JTA (was sinnvoll ist, und in der Regel wünschenswert), so dass die Ausnahme die ich habe fangen wollen, wurde nicht geworfen noch.

Ich denke, was ich will, ist in der Lage sein zu definieren, die eine Ausnahme-filter, der angewendet wird nach JTA seine Sache macht. Irgendwelche Ideen?


Ich arbeite mit JBoss AS 7.1.1.Endgültig und EclipseLink 2.4.0. EclipseLink installiert ist, als ein JBoss-Modul wie pro diese Anweisungenaber das spielt keine große Rolle für die Frage auf der hand.


UPDATE: Nach mehr Gedanken zu diesem Thema, habe ich realisiert, dass zusätzlich zu JSR330 Validierung Ausnahmen, die ich wirklich auch in der Lage sein müssen trap SQLIntegrityConstraintViolationException aus der DB und deadlock oder Serialisierung Fehler rollbacks mit SQLSTATE 40P01 und 40001 bzw.. Deshalb ist ein Ansatz, der gerade versucht, stellen Sie sicher, verpflichten, nie werfen wird nicht funktionieren. Checked exceptions der Anwendung kann nicht geworfen werden, die durch eine JTA Begehen, weil die JTA-Schnittstellen natürlich nicht deklarieren, aber nicht aktiviert @ApplicationException kommentierten Ausnahmen sollten in der Lage sein werden.

Es scheint, dass dort, wo ich sinnvollerweise fangen Sie eine Anwendung Ausnahme, kann ich auch - wenn auch weniger hübsch - fangen Sie eine EJBException, und Tauchen Sie ein in es für die JTA-Ausnahme und die zugrunde liegende Validierung oder JDBC exception, dann tun Sie Entscheidungen auf dieser Grundlage. Ohne eine Ausnahme-filter-Funktion in JTA-werde ich wohl müssen.

InformationsquelleAutor der Frage Craig Ringer | 2012-08-02

Schreibe einen Kommentar