Using JavaCompiler with Classpath referencing jars within ear - classpath

I am working on a project in which an enterprise archive (ear) deployed on a JBoss server needs to compile (and run) a class dynamically. I am using the JavaCompiler class to do this - the complication comes from the fact that the class being compiled has references to some of the classes contained within the ejb jar within the ear.
This is not a problem when the deployed ear is 'exploded' on deployment, so it is just a directory rather than an archive - in this case I am able to specify the required jar in the -classpath option of the compiler, and compilation works fine. Unfortunately due to constraints of the systems I am working with, it is not an acceptable solution to deploy these ears 'exploded', and the compiler seems not to be able to 'see' the required jar when it's wrapped up in an archive.
Given that the dynamic compilation is taking place from the ear in question, and therefore the system's class loader has access to the contents of the required jar, is there any way I can tell the compiler to just use the classes as loaded by the system class loader?
I appreciate this is something of a wordy question, but any help would be appreciated.
Thanks

It seems that there is no simple way to have the JavaCompiler load dependencies of compiled code from a ClassLoader. However, one could implement JavaFileManager directly and redirect the operations for the StandardLocation.CLASS_PATH using resource lookups on the context ClassLoader (getResource(<class/resource name>)). This would withdraw the limitation of StandardJavaFileManager directly operating on Files.
Someone already seems to have prototypically implemented that approach:
http://atamur.blogspot.de/2009/10/using-built-in-javacompiler-with-custom.html

Related

What is a bundle resource path in class loader? How do I access that path?

I have a web application deployed to Websphere and found that there are some conflicting jars. To find the path of the conflicting class I have added the below code
ClassLoader classLoader = MyClass.class.getClassLoader();
URL resource = classLoader.getResource("org/apache/http/conn/ssl/AllowAllHostnameVerifier.class");
System.out.println(resource);
When I check the IBM System.out log file I see the below path for resource. I am not sure what bundle resource path is. I would like to know how do I access the below location?
bundleresource://85.fwk734572965/org/apache/http/conn/ssl/AllowAllHostnameVerifier.class
"bundleresource" URLs represent entries from the OSGi framework class loader. The number maps to a bundle number in the OSGi configuration, which you can find by opening up the OSGi console (from the WAS_HOME/bin directory, osgiConsole.sh|bat -server <servername>) and running the "ss" command, which lists the bundles along with their state and numerical ID.
Assuming you're seeing a conflict at runtime through class loading (not actually pulling in these classes through getResource), I'll say with fairly strong certainty that you're picking up the conflicting classes from the JAX-RS prereq jar, WAS_HOME/plugins/com.ibm.ws.prereq.jaxrs.jar. At the time it shipped, that jar made its copy of Apache HTTP visible to applications. That visibility was removed in a later fixpack, if you're able to patch up your installation to the latest service level.
Note that even if you move to a newer fixpack with that fix, your testcase will probably still show the same thing - I don't think that getResource() is subject to the same filtering as loadClass(), so you might still be able to get at the .class file in that manner. It might help with the issues you're seeing at runtime, though.

AspectJ aspect not called for loaded classes

In a RCP osgi based application, i want to load classes from disc at runtime. This loading is independent from OSGI infrastructure.
I have a custom classloader, which can do this and works in general (without the AspectJ).
Now these loaded classes shall have aspects applied.
But the aspect code is not called.
I have the .class files build with Ant iajc compiler. Do I need load-time weaving?
When load-time weaving is needed, is it sufficient to add the dependency "org.aspectj.weaver" and make the classloader extend WeavingURLClassLoader?
If it is WeavingURLClassLoader, can i use this URL to point to an aspect, located in another plugin? "platform:/plugin/myplugin/my_package/Aspect.aj". Or without the .aj extension?
How can debug this?
Frank
.
I have got it working now.
using the ctor WeavingURLClassLoader( classesUrls, aspectUrls, parent ).
Where classesUrls needed to be a URLs to folder or Jar. This must include the aspectj runtime jar.
aspectUrls needed to be a URLs to folder or Jar. This must not include the aspectj runtime jar.
URL pointing to specific aspect files within the jars do not work. The trial to use a OSGI bundle URL, did not work. For me, i needed find the JAR files directly on the file system.

Don't load/scan class files from a specific jar

I'd like to know how to configure the maven-bundle-plugin (backed by bnd) to completely ignore the classes contained within an embedded jar.
Background
I'm working in a controlled environment where the environment my code is running on is defined by a single company (including all the tools). The code is java and uses OSGi to define module dependencies.
Some of the provided modules contain what look like invalid class files, I can only assume that the system will 'correct' these class files before it tries to load them into any type of JVM. In any case these class files work when deployed onto the target system.
I'm trying to create a build system based on Maven that can produce packages the system understands and have hit a problem where these invalid class files are being read by BND (via apache-felix) which causes errors.
I'd like a way to have the jars that contain these class files on the class path of the bundle but where the contained .class files aren't read/processed by bnd. I could settle for simply ignoring the errors and continuing but can't find a way to do that either without felix aborting the entire build phase.
I just found the -failok directive, don't know why I didn't find it before. Adding <_failok>true</_failok> to the instructions allows me to continue working.
See instructions-ref

How can you develop bottom-up JAX-WS web services referencing classes contained in separate jar files?

I am developing a Java EE 6 bottom-up JAX-WS to expose an EJB3.1 stateless session bean. The web service in a WAR is failing to install on deployment because it references an external jar (or shared library) which one can assume is not loaded yet.
The common suggestion is to include the jars in the /lib folder, which does fix the issue, however the jars need to remain in this external shared library location and NOT in the ear file, because they amount to 30MB.
What are some techniques to get around this issue in a Websphere (WAS v.8) environment or any server environment.
Some suggestions I have found include:
1. define classpath in META-INF file.
2. define the resources in deployment.xml
3. alter class loading order
4. (from ibm) In the case where the jars are part of a Shared Library configured on WebSphere Application Server, then a User Library must be used to configure the project for development before generating the WebService.
However, I have been unsuccessful to find any help online in these areas. Is there another technique or does anyone know anything about accomplishing this? Thanks in advance.
EDIT: If I specify the libraries in the META-INF using class-path, they are loaded before extensions, shared libraries..etc, but they are still loaded after the WAR which is not good. Again, this isn't a runtime issue because the web services are created at deployment on the fly.
I submitted a ticket to IBM. The libraries referenced by the web service are needed during deployment and must be bundled into the Ear in some fashion. I threw them in the web-inf/lib folder. However, if the referenced libraries then depend on additional libraries, these can be placed in the Shared Libraries. Seems odd to me too, but let's all just admit "shared libraries" are a hack anyways.
If you still have issues, just make sure your class loading is set to parent_last.

Deployment Concepts: Packaging JAR Dependencies, When & Why

So I'm relatively new to Java EE and I am having a tough time understanding when, where and why Java deployment files are packaged with their dependencies.
Say I build my project into myapp.jar, and it depends on fizz.jar, buzz.jar and JODA (joda-time-2.0.jar).
I've heard that the default classloader doesn't package jars inside of other jars, so I have to assume that if I called a jar task from Ant, then the default classloader would get invoked and myapp.jar would be created without those 3 dependencies in it.
Is this because the mentality is to deploy main-less jars in containers or other systems that will provide its requirements at runtime? If not, then how does myapp.jar ever run correctly?
What about executable jars? To met, these must be different than main-less jars, because they are meant to be standalone units, right? That means they would need all of their dependencies packaged with them, right?
Last but not least, what about jars that depend on jars that depend on jars...etc. (i.e., dependencygraphs that are huge)?
I guess all of these questions can be summed up as follows:
Is the idea behind a non-executable jar that it will be ran in such a way that it will know what classpath(s) to look on for its dependencies at runtime? (And thus doesn't need to be packaged with its dependencies)?
Is the idea behind an executable jar that it is a standalone unit and should be pacakged with its dependencies?
If my assertion to Question #1 above is correct, how does such classpath configuration take place? Are these settings that are stored inside the jar (such as in the manifest)? Else, how would a JRE know where to search for a particular jars dependencies at runtime?
Answers to these questions will actually clarify quite a lot of hangups I have with Java fundamentals, and so any input/help here will be appreciated enormously! Thanks
Jars do not know about other jars (unless assisted by some tools like Maven). The inter dependency of the jars is purely resolved by the Classloaders. I strongly recommend to have some idea about classloaders.
To address your questions,
Is the idea behind a non-executable jar that it will be ran in such a way that it will know what classpath(s) to look on for its dependencies at runtime? (And thus doesn't need to be packaged with its dependencies)?
NO. As mentioned, it's the classloader which looks the classpath and the jars mentioned therein. The jars do not have any information about other jars.
Is the idea behind an executable jar that it is a standalone unit and should be packaged with its dependencies?
NO. A classloader loads the standalone executable jars at the start of execution. If it needs other dependency jars it'll look into the classpath for those jars.
If my assertion to Question #1 above is correct, how does such classpath configuration take place? Are these settings that are stored inside the jar (such as in the manifest)? Else, how would a JRE know where to search for a particular jars dependencies at runtime?
For standalone jar (executable jar), the classloader looks for the classpath variable OR classpath passed while invoking the application.
For other type of application (WAR, EAR), There are predefined places/folders where the dependencies should be placed in order to get picked up. This is standardized by specs.
In a nutshell, it's the classloader which is pulling all the threads. There is standard places where it looks for all the dependent jars. This link nicely describes how the classloaders in standalone application and in a deployed (in some container) works.
JAR files are a way to package togher complex java application. Jar application are easy to move between diffrent machines and operating system.
I think the right way to use Jars is not tu put everything (every dependencies) into a single jar.
For example if your application uses a jar libryra (for example jdbc) to access a database you should not put the jdbc jar into your jar.
You had better to build a jar file with only your .class file.
Of course your code needs the jdbc jar to work properly. Here comes to explain how the virtual machine searches for extarnal classes:
-it first searches in the directories that contain the classes that come standard with J2SE (the path depends on your installation)
-it searches in the directories specified by the classpath (a classpath is either an environment variable or an option of the java command)
for example:
java -jar -c /your/path/ yourApp.jar
will run your application and will search th classes your application refers to in the directory /your/path/ so if you have external jars you can put them in that directory.
For detailed documentation: http://download.oracle.com/javase/tutorial/deployment/jar/index.html