@TransactionAttribute annotations on private EJB methods

@TransactionAttribute annotations on private EJB methods

Keine Kommentare zu @TransactionAttribute annotations on private EJB methods

Last week Frank Schwarz published a post (german language) on the buschmais company site about a common misuse of @TransactionAttribute annotations on private methods of EJBs (Enterprise Java Beans):

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

In short words: this code is useless – the container will not start any transaction. The EJB 3.1 spec states:

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

TL;DR: @TransactionAttribute are only allowed on public methods

Frank also provides a proposal how this problem can be detected using static code analysis based on PMD.

Let’s try the same with jQAssistant – all we need is a constraint:

<constraint id="ejb3:TransactionAttributeOnlyAllowedOnPublicMethods">
  <description>@TransactionAttribute annotations are only allowed on public methods.</description>
  <cypher><![CDATA[
    MATCH
      (type:Type)-[:DECLARES]->(method:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(transactionAttribute)
    WHERE
      transactionAttribute.fqn = "javax.ejb.TransactionAttribute"
      and not method.visibility = 'public'
    RETURN
      type.fqn as EJB, method.signature as Method 
  ]]></cypher>
</constraint>

Let’s improve the constraint a bit – currently only methods are validated but the annotation might also be misplaced on public methods of classes which are not EJBs. The Java EE 6 plugin provides some useful rules to make life easier for this case so we’re going to activate it, e.g. in the case of Maven:

<plugin>
  <groupId>com.buschmais.jqassistant.scm</groupId>
  <artifactId>jqassistant-maven-plugin</artifactId>
  <version>${org.jqassistant_version}</version> <!-- e.g. 1.0.0 -->
  ...
  <dependencies>
    <dependency>
      <groupId>com.buschmais.jqassistant.plugin</groupId>
      <artifactId>jqassistant.plugin.javaee6</artifactId>
      <version>${org.jqassistant_version}</version>
    </dependency>
  </dependencies>
</plugin>

The improved constraint looks as follows:

<constraint id="ejb3:TransactionAttributeOnlyAllowedOnPublicMethodsOfEJBs">
  <requiresConcept refId="ejb3:MessageDrivenBean" />
  <requiresConcept refId="ejb3:SingletonBean" />
  <requiresConcept refId="ejb3:StatefulSessionBean" />
  <requiresConcept refId="ejb3:StatelessSessionBean" />
  <description>@TransactionAttribute annotations are only allowed on public methods of EJBs.</description>
  <cypher><![CDATA[
    MATCH
      (type:Type)-[:DECLARES]->(method:Method)-[:ANNOTATED_BY]->()-[:OF_TYPE]->(transactionAttribute)
    WHERE
      transactionAttribute.fqn ="javax.ejb.TransactionAttribute"
      and not (type:Ejb and method.visibility = 'public')
    RETURN
      ejb.fqn as Type, method.signature as Method 
  ]]></cypher>
</constraint>

All concepts required by the constraint add a label „Ejb“ to types which are Enterprise Java Beans and the where clause has been extended to verify that this label is present on the declaring type.

About the author:

@dirkmahler

Leave a comment

Back to Top