问题
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.
回答1:
I may be missing something obvious here but... Isn't GlassFish Embbeded shipped with libraries compatible with the Java EE specs? And aren't those libraries loaded by default? (If they aren't, please fill a bug here: http://java.net/jira/browse/EMBEDDED_GLASSFISH).
What I mean is: You should compile against Java EE spec APIs, and just let the container use it's own implementations.
For the first part, if you use Maven, I like the way Codehaus archetypes sets the endorsed libs. It is both clean and Application Server Agnostic:
<properties>
<endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArguments>
<endorseddirs>${endorsed.dir}</endorseddirs>
</compilerArguments>
</configuration>
</plugin>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${endorsed.dir}</outputDirectory>
<silent>true</silent>
<artifactItems>
<artifactItem>
<groupId>javax</groupId>
<artifactId>javaee-endorsed-api</artifactId>
<version>6.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
Which is pretty much all you need to compile your projects against Java EE 6 APIs. Any Java EE 6 compliant App Server should provide those services, and you shouldn't be worried about how they are making it available to your application.
The responsibility of bootstrapping Java EE Services should be of your App Server. If you try your own "in house" solution, chances are that JAR Hell will break loose.
Cheers,
回答2:
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 ofSystem.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 namedjavaxAnnotationVersion
, which, for me, is set to3.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.
来源:https://stackoverflow.com/questions/6439368/any-best-practices-for-dealing-with-java-ee-and-java-endorsed-dirs