Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any best practices for dealing with Java EE and java.endorsed.dirs?

I've recently run into a problem with glassfish standalone (v3.1) vs glassfish embedded (v3.1) vs java SE and the way java.endorsed.dirs is used. The specific problem I had is here, but I don't think it's the last time I'm going to run into something similar.

The information I found here and here suggests adding the glassfish endorsed libs to the bootstrap classpath when compiling. However, this bug report suggests it is difficult to get the endorsed libs set correctly when using glassfish embedded.

So, it seems like when I deploy to a standalone glassfish container my application is going to run against the endorsed libs that glassfish includes, but when using the embedded container it won't. I encountered my original problem because the maven-embedded-glassfish-plugin doesn't start glassfish embedded using the endorsed libs like glassfish standalone does. I'm also unsure whether other containers (ex: jboss) include the same set of endorsed libs as glassfish.

So, am I (1)supposed to struggle (a lot) to make sure my application is compiled against the endorsed libs and always deployed to a container that is bootstrapped using the endorsed libs or should I (2)just stick to using what's bundled with Java SE 6?

If I choose (2), will I have to worry about incompatibilities when deploying my application to a container that is bootstrapped with newer endorsed libs?

I would appreciate any insight that anyone can offer.

like image 423
Ryan J Avatar asked Jun 22 '11 11:06

Ryan J


1 Answers

EDIT: The javaee-endorsed-api approach above probably will work fine, but it gives me the willies. I don't think it is produced or maintained anymore. Furthermore the pom.xml it contains within it reflects that at some point it was called javaee-compact-api, and you can see how they strip the implementation classes out of it. By contrast, cherry-picking the API jars you want to use as endorsed (as I recommend below) seems to be more stable and flexible. Finally, if you still want to use the javaee-endorsed-api approach, you can still use the general approach I recommend and point to javaee-endorsed-api.jar instead.

Ryan; I just combed through your long trail on this (touching StackOverflow, the java.net forums, etc.) on the same journey.

During unit or integration testing you'll need to set the java.endorsed.dirs System property, as you know.

The trick is you have to do this in such a way that the JVM running the tests picks it up. And that depends on how you have Surefire running.

If for some reason you have Surefire set to not fork, this is probably a bad thing, and you should re-evaluate your configuration here.

If you have Surefire set to fork, then you might think you could simply include java.endorsed.dirs in a systemPropertyVariables stanza, like this:

<systemPropertyVariables>
  <java.endorsed.dirs>weWillGetToThisInAMoment</java.endorsed.dirs>
</systemPropertyVariables>

...but that would be wrong. The reason is that the program that is actually running is something called the ForkedBooter, and the ForkedBooter programmatically sets system properties for your unit tests. That is, by the time your <systemPropertyVariables> stanza is read by the ForkedBooter it's already too late.

But you can use <argLine> in your Surefire configuration like this:

<configuration>
  <argLine>-Djava.endorsed.dirs=weWillGetToThisInAMoment</argLine>
</configuration>

Now the VM that Surefire forks will have its endorsed directories set appropriately. Now let's talk about what value to supply.

You want to cherry pick the APIs to override. In your case, javax.annotation.* is a legitimate choice. You want to supply the directory in your local Maven repository that houses the relevant jar.

Here is the value that I use:

${settings.localRepository}${file.separator}org${file.separator}glassfish${file.separator}main${file.separator}javaee-api${file-separator}javax.annotation${file.separator}${javaxAnnotationVersion}
  • Maven guarantees that ${settings.localRepository} will expand to the value of where your local Maven repository lives.
  • ${file.separator} is a way of getting the value of System.getProperty("file.separator") in a Maven property replacement.
  • In my case, I've already declared a <dependency> on the GlassFish artifact that bundles up the javax.annotation package as defined in Java EE 6. So here I've constructed a path to the artifact. I've also defined a property named javaxAnnotationVersion, which, for me, is set to 3.1.2.

Once you do all of this, then when Surefire forks a VM to run your unit tests, the endorsed directories will be set to the directory in your local Maven repository containing the jar that houses the javax.annotation classes, and now embedded GlassFish—which runs in-process—will use the Java EE 6 versions of javax.annotation classes instead of the Java SE 6 versions. I hope this helps you out.

like image 56
Laird Nelson Avatar answered Sep 27 '22 22:09

Laird Nelson