@TransactionAttribute annotations on private EJB methods
@TransactionAttribute annotations on private EJB methods
12. Juni 2015 Keine Kommentare zu @TransactionAttribute annotations on private EJB methodsLast 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.
Leave a comment