Adam Bien's Weblog
Trouble With Crippled Java EE 6 APIs in Maven Repository And The Solution
If you try to load the javax.persistence.EntityManager class coming from standard java.net Repository you will get the following Exception:
java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/persistence/LockModeType
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
Loading a class is needed for mocking, so the following code will not run:
@Stateless
public class EJB3WithEntityManager {
@PersistenceContext
EntityManager em;
public void save(AnEntity ae){
em.persist(ae);
}
}
public class EJB3WithEntityManagerTest {
private EJB3WithEntityManager cut;
@Before
public void injectEntityManager(){
this.cut = new EJB3WithEntityManager();
this.cut.em = mock(EntityManager.class);
}
@Test
public void testSomeMethod() {
AnEntity ae = new AnEntity();
this.cut.save(ae);
verify(this.cut.em,times(1)).persist(ae);
}
}
Instead of using
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
You should use alternative (geronimo, jboss etc.) dependencies:
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-ejb_3.1_spec</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jpa_2.0_spec</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
I cannot imagine any reasonable motivation behind removing the implementation of API-classes before uploading them into central maven repository, except political or licensing issues. This approach, however, has one advantage. You can tell whether a project is actually unit tested, or not, just by looking at the POM :-).
The whole example with workaround was checked into http://kenai.com/projects/javaee-patterns The name of the project is:
MavenUnitTestWithCrippledAPI.
Posted at 11:44AM Oct 20, 2010 by Adam Bien in Real World Java EE Patterns - Rethinking Best Practices | Comments[15] | Views/Hits: 17155
NEW Workshop: "JPA, NoSQL, Caching, Grids and Distributed Caches with Java EE 7", May 7th, 2013, Airport Munich
A book about rethinking Java EE Patterns
Tweet Follow @AdamBien

You don't have to swap the dependencies - it's enought to have the implementations in "test" scope *before* the API dependency:
e.g. Eclipselink for an outside-of-container test of a glassfish project:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc5</artifactId>
<version>11.2.0.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<scope>provided</scope>
<version>6.0</version>
</dependency>
Posted by Matthias Fraass on October 20, 2010 at 01:53 PM CEST #
@Matthias,
but why? They are "provided" anyway. Just going with one set of dependencies makes the POM shorter. javaee-web-api is the WEB-API, and the other dependencies are the API with implementation.
thanks!,
adam
Posted by adam-bien.com on October 20, 2010 at 02:10 PM CEST #
Hi, you also could use different profiles.
The test profile could then use the implementation-jar.
The profile for generating the product could use the api-jar.
Posted by Stefan Bohn on October 20, 2010 at 03:53 PM CEST #
you are right, you can omit that.
Posted by Matthias Fraass on October 20, 2010 at 04:58 PM CEST #
@Stefan,
sure. Instead of using the bogus Java EE 6 class files, I would just use the "real" implementations and not refer to the Java EE 6 API at all.
But in general - you are right :-)
The real problem is the bogus JAR in maven repo. Our ideas are just workarounds :-)
thanks for your thoughts!,
adam
Posted by adam-bien.com on October 20, 2010 at 05:07 PM CEST #
It was my understanding that the reason they are not in the central repo is licensing issues. :(
Posted by jkilgrow on October 20, 2010 at 06:49 PM CEST #
@jkilgrow,
could be. I guess even warranty claims or something like that. The problem are a few abstract classes with removed implementation. They could be implemented from scratch without any implementation in hours if not minutes.
I guess it would solve several millions of man hours worldwide :-)
thanks!,
adam
Posted by adam-bien.com on October 20, 2010 at 09:28 PM CEST #
there is other solution if you are using maven >=2.0.9
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.0.CR2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<scope>provided</scope>
</dependency>
more information:
http://stackoverflow.com/questions/2116220/how-can-i-use-different-jars-for-compiling-and-testing-in-maven
Posted by 89.72.75.239 on October 20, 2010 at 10:50 PM CEST #
@89.72.75.239,
(you have a geeky name :-)).
Sure - it is identical to the @Matthias suggestion.
But I would just use Hibernate, without javaee-web-api then.
thanks for the link,
adam
Posted by adam-bien.com on October 20, 2010 at 11:07 PM CEST #
I think it's not licensing nor warranty concerns (that missing code is trivial). I think it's just that it's not part of the spec! The implementers could choose to do some specific stuff in there... but your unit tests should not depend on those.
Instead of removing the code, it would be nicer to have all methods throw an exception instead, wouldn't it?
But I wonder why you're having problems with the EntityManager. That is an interface, so there should be no code block missing and the mocking should work!
Rüdiger
Posted by Rüdiger on October 21, 2010 at 02:14 PM CEST #
Wasn't one of the goals of Gemini to expose Java EE 6 and related artifacts in a better way ?;-)
JSR-330 is another hilarious example.
After PFD-1
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1.0-PFD-1</version>
</dependency>
which caused a whole bunch of online flames especially from EE stakeholders
it ended up as this:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
Quick and Dirty and a bit love-less I'd say, others in the JCP call that "Agile" ;-|
Posted by Werner Keil on February 06, 2011 at 04:40 PM CET #
Other way is to use:
<dependency>
<groupId>org.glassfish.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>3.1</version>
<scope>provided</scope>
</dependency>
with
<repository>
<id>java.net</id>
<name>GlassFish Maven Repository</name>
<url>http://download.java.net/maven/glassfish</url>
</repository>
Then you have all dependencies including javax.validation.
Posted by Przemysław Pelczar on July 18, 2011 at 01:48 PM CEST #
Hi all,
I found a nice workaround on Arquillian wiki (https://community.jboss.org/wiki/WhatsTheCauseOfThisExceptionJavalangClassFormatErrorAbsentCode). It seems to work for me, even with non-Arquillian tests.
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<classpathDependencyExcludes>
<!-- exclude code absent api -->
<classpathDependencyExclude>javax:javaee-api</classpathDependencyExclude>
<classpathDependencyExclude>javax:javaee-web-api</classpathDependencyExclude>
</classpathDependencyExcludes>
</configuration>
</plugin>
Posted by Alexis on April 03, 2012 at 06:51 AM CEST #
Another ugly thing is that these javax API classes in the maven repository do not come with sources or API. No fun debugging or just hovering ;-)
@Adam: Thx for your always informative blogs!
Posted by Jan Wiemer on April 06, 2012 at 12:37 AM CEST #
@Alexis: thanks, your workaround worked for me beautifully. I am getting a similar error as that posted here but instead related to javax-rpc.
Posted by Brandon on October 13, 2012 at 12:26 AM CEST #