EJB-TX-Annotationen an privaten Methoden

Mit erstaunlicher Hartnäckigkeit hält sich ein Phänomen in JavaEE Anwendungen: @TransactionAttribute an privaten Methoden. So nutzlos wie irreführend, dokumentiert es die Unkenntnis des Entwicklers über die Mechanismen eines EJB-Containers:

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
private void doSomething() {
  // start a new transaction
  ...
}

Diese Code ist überaus suggestiv und wird gerne in Code-Reviews übersehen. Eine neue Container-Transaktion wird dennoch nicht gestartet. Hierfür müsste der Container einen Interzeptor um den Aufruf von “doSomething()” wickeln. Das wäre einerseits eine große technische Herausforderung und ist andererseits in keiner Weise durch die EJB-Spezifikation gedeckt.

Hierzu die EJB 3.1 Spec:

TL;DR: @TransactionAttribute gehört nur an Public-Methoden

A transaction attribute is a value associated with each of the following methods

  • a method of a bean’s business interface
  • a method exposed through the bean class no-interface view

(Kapitel 13.3.7, Hervorh. d. Verf.)

Der “No-Interface View” ist definiert als:

A Session Bean’s no-interface view is a variation of the Local view that exposes the public methods of the bean class without the use of a separate business interface.” (Kapitel 3.4.4, Hervorh. d. Verf.)

Automatische Prüfung mit PMD

Um die Annotation @TransactionAttribute an privaten Methoden automatisch zu erkennen, bietet sich PMD an. Dieses Werkzeug läuft oft im Build-Prozess schon mit und muss dann nur um eine Regel erweitert werden. Dies klingt komplizierter, als es tatsächlich ist.

PMD erzeugt einen Abstract-Syntax-Tree (AST) von Java-Source-Dateien. Auf diesem Baum können XPath Abfragen ausgeführt werden. Eine Ganze verpackt man in eine XML Datei und meldet diese Datei im Maven-PMD-Plugin an.

Zunächst die Regel:

//MethodDeclarator[
    ../@Public='false' and 
    ../../Annotation//Name[@Image='TransactionAttribute']
  ]

Keine Sorge! Zur Erstellung der Regel ist kein langwieriges Handbuchstudium notwendig. In der PMD-Distribution ist ein Tool namens “designer” enthalten. Dies ist eine Swing-Anwendung, die aus Java-Code einen Abstract-Syntax-Tree erzeugt. Mit dem PMD-Designer lassen sich Ad-Hoc Abfragen auf dem AST ausführen und das Ergebnis begutachten.

PMD-Designer

Diese Regel verpackt man in eine XML-Datei:

<?xml version="1.0"?>
<ruleset name="Custom ruleset" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
  <description>
    This ruleset checks for bad JavaEE usage patterns
  </description>
  <rule name="TransactionAttributes" 
    language="java"
    message="Avoid @TransactionAttribute on non-public method ''{0}''."
    class="net.sourceforge.pmd.lang.rule.XPathRule">
    <description>Private methods must not be annotated with @TransactionAttribute</description>
    <priority>1</priority>
    <properties>
      <property name="xpath">
        <value>
           //MethodDeclarator[../@Public='false' and ../../Annotation//Name[@Image='TransactionAttribute']]
        </value>
      </property>
    </properties>
    <example>
@Stateless
public class MyService {
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
  private void somePrivateMethod() {
    // transaction attributes are not honored on non-business methods
  }
}
    </example>
  </rule>
</ruleset>

Hierzu nur eine kurze Anmerkung: Möchte man eine aussagekräftige Fehlermeldung, sollte das gefundene AST-Element ein “Image“-Attribut aufweisen (hier: “MethodDeclarator“).

Die XML-Regel-Datei muss noch in der Maven-Plugin-Konfiguration referenziert werden:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-pmd-plugin</artifactId>
   <version>3.4</version>
   <configuration>
     <rulesets>
       <ruleset>${basedir}/src/pmd/rules.xml</ruleset>
       <!-- weitere Regeln -->
     </rulesets>
  </configuration>
</plugin>

Danach startet den Build-Prozess mit …

mvn clean install pmd:pmd

.. und kann das Ergebnis unter ${basedir}/target/site/pmd.html bestaunen.

PMD-Result

Kommentare sind abgeschaltet.