AspectJ aspect not called for loaded classes - aspectj

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.

Related

Using JavaCompiler with Classpath referencing jars within ear

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

#MappedSuperclass static weaving with EclipseLink and multiple jars

My entities objects are scattered in multiple jars.
In jar A I have a base class name MyBase which is annotated with #MappedSuperclass.
In jar B there is an entity class which derives from MyBase.
The problem is that because the weaving is done in the context of the jar file (I'm using the maven plugin) the base class (MyBase) isn't instrumented (although it should).
If I move the derived class from jar B to A then the weaving process will handle the base as well.
Since I'm working on a large project it is critical for me to develop in a modular way.
Doesn't EclipseLink support such methodology?
The only way I found to override this limitation is to add a temporary entity class to the jar where the #MappedSuperclass base class is defined and remove it after the weaving procedure.
Sad, but true ;-)
I'm not sure on the maven plugin, but you should be able to use the static weaver on both jars, you will need to call it twice to weave both, and will need both jars on the weavers classpath for both calls.
Alternatively you can specify the jar containing your superclass as inpath - as explained here and here:
Managing multiple projects
Building AspectJ source code requires two distinct phases; compiling
the source in .java and .aj files to generate .class files, and then
applying the aspects to the generated .class files. This second phase,
known as weaving, is the key difference between AspectJ and Java
compilers. The Java compilation process is controlled by the classpath
setting, which makes types available for resolution by the compiler.
The same classpath setting is used by the AspectJ compilation process
and it is configured in exactly the same way in Eclipse. However, this
setting is not sufficient to control both the compilation and weaving
steps in all situations. This is why there are two extra settings
available for AspectJ projects.
First, there is the inpath setting. Anything specified here will be
made available to the weaver and so any aspects that apply will be
woven in. Entries can be added to a project's inpath by right-clicking
on the project, selecting Properties, then going to the AspectJ InPath
section. Entries can be either JAR files or directories (class
folders), such as the bin directory of another project. Anything on
the inpath is sent to the project's output, after potentially being
woven with aspects.
The second additional setting is the aspectpath. Whereas the inpath
controls the list of things that get woven, the aspectpath controls
what is woven into that list. In other words, any aspects specified on
the aspectpath are made available to the weaving process, just as if
they were present in source form in the project. This setting is
controlled from the AspectJ Aspect Path property page and can contain
either JAR files or directories.
An output JAR setting is also present in the AspectJ section of each
project's property page. This setting causes the compiler to output
class files directly to a JAR file, instead of to the project's output
folder.
Drove me crazy just like you - hope this helps. ;)

Exporting Eclipse RAP war with OSGi bundles with external bundle-path

I have an Eclipse RAP product, I like to export as a web app for use inside Tomcat. For this I use the warproduct exporter in Eclipse, which until now have worked fine.
I have a problem with compilation of one of the OSGi bundles in the product as this refers to a set of external jars using a variable substitution. This is shown in the following fragment from a MANIFEST.MF:
Bundle-Name: ...
Bundle-SymbolicName: ...
Bundle-ClassPath2: external:/A/test1/jakarta-tomcat/shared/lib/a_base.jar
Bundle-ClassPath: external:$A_HOME$/jakarta-tomcat/shared/lib/a_base.jar
If I use the first classpath instead and have the correct /A/test1/jakarta-tomcat/shared/lib/a_base.jar in place, then everything is fine during the compilation... And I can even manually change the MANIFEST.MF afterwards to the correct version with the substitution.
But, I would really like to avoid this extra step, if at all possible!
I think the question is how to pass in a proper value for A_HOME during the compilation?
(Why do this? Above, I just shown a single jar file, but we have a larger number of jar files we want to share between our older Tomcat applications and the newer RAP based application. We know, there are other ways of sharing jars in this situation - e.g. via an OSGi framework extender or the extendedFrameworkExports initialization parameter in web.xml - but we need the chosen method as we use EMF and therefore cannot share the EMF meta data between Tomcat and Eclipse... And thus not the class objects...)
this feature is currently not support within the WAR Products Tooling. I recommend to open a bug against Eclipse Libra and to define the feature request their. Anyway, we have created an example how to build a RAP application with tycho which is pretty easy, maybe you want to take a look: https://github.com/eclipsesource/rap-mobile-demos
Cheers Holger

How to add JAR libraries to WAR project without facing java.lang.ClassNotFoundException? Classpath vs Build Path vs /WEB-INF/lib

How should I add JAR libraries to a WAR project in Eclipse without facing java.lang.ClassNotFoundException or java.lang.NoClassDefFoundError?
The CLASSPATH environment variable does not seem to work. In some cases we add JAR files to the Build Path property of Eclipse project to make the code compile. We sometimes need to put JAR files inside /WEB-INF/lib folder of the Java EE web application to make the code to run on classes inside that JAR.
I do not exactly understand why CLASSPATH does not work and in which cases we should add JARs to Build Path and when exactly those JARs should be placed in /WEB-INF/lib.
The CLASSPATH environment variable is only used by the java.exe command and even then only when the command is invoked without any of the -cp, -classpath, -jar arguments. The CLASSPATH environment variable is ignored by IDEs like Eclipse, Netbeans and IDEA. See also java.lang.ClassNotFoundException in spite of using CLASSPATH environment variable.
The Build Path is only for libraries which are required to get the project's code to compile. Manually placing JAR in /WEB-INF/lib, or setting the Deployment Assembly, or letting an external build system like Maven place the <dependency> as JAR in /WEB-INF/lib of produced WAR during the build, is only for libraries which are required to get the code to deploy and run on the target environment too. Do note that you're not supposed to create subfolders in /WEB-INF/lib. The JARs have to be placed in the root.
Some libraries are already provided by the target JEE server or servletcontainer, such as JSP, Servlet, EL, etc. So you do not need put JARs of those libraries in /WEB-INF/lib. Moreover, it would only cause classloading trouble. It's sufficient to (indirectly) specify them in Build Path only. In Eclipse, you normally do that by setting the Targeted Runtime accordingly. It will automatically end up in Build Path. You do not need to manually add them to Build Path. See also How do I import the javax.servlet / jakarta.servlet API in my Eclipse project?
Other libraries, usually 3rd party ones like Apache Commons, JDBC drivers and JEE libraries which are not provided by the target servletcontainer (e.g. Tomcat doesn't support many JEE libraries out the box such as JSF, JSTL, CDI, JPA, EJB, etc), need to end up in /WEB-INF/lib. You can just copy and paste the physical JAR files in there. You do not necessarily need to specify it in Build Path. Only perhaps when you already have it as User Library, but you should then use Deployment assembly setting for this instead. See also ClassNotFoundException when using User Libraries in Eclipse build path.
In case you're using Maven, then you need to make absolutely sure that you mark libraries as <scope>provided</scope> if those are already provided by the target runtime, such as JEE, Servlet, EL, etc in case you deploy to WildFly, TomEE, etc. This way they won't end up in /WEB-INF/lib of produced WAR (and potentially cause conflicts with server-bundled libraries), but they will end up in Eclipse's Build Path (and get the project's code to compile). See also How to properly install and configure JSF libraries via Maven?
Those JARs in the build path are referenced for the build (compile) process only. If you export your Web Application they are not included in the final WAR (give it a try).
If you need the JARs at runtime you must place them in WEB-INF/lib or the server classpath. Placing your JARs in the server classpath does only make sense if several WARs share a common code base and have the need to access shared objects (e.g. a Singleton).
If you are using Maven:
Open the project properties, and under Deployment Assembly click Add...
Then select Java Build Path Entries and select Maven Dependencies
Resolved by setting permissions.
Had related issue using PySpark and Oracle jdbc. The error does not state that the file cannot be accessed, just that the class cannot be loaded.
So if anyone still struggles, check the permissions. Some might find it obvious tho'.
I want to give the answer for the folowing link question ClassNotFoundException oracle.jdbc.driver.OracleDriver only in servlet, using Eclipse
Ans: In Myeclipse go to Server-->left click on Myeclipse Tomcat7-->Configure Server Connector-->(Expand)Myeclipse Tomcat7--> Paths-->Prepend to classpath-->Add jar (add oracle14 jar)-->ok

how to properly bundle GWT with my webapp? (was: why gwt-user-1.7.0 contains Servlet API classes)

Does anyone know any sane reason for such bundling decision? Google engineers act wisely in most cases, so this kinda surprized me.
This would cause collisions with other versions of servlet API pulled via Maven dependencies:
webapp classpath will likely contain
version which is bundled with GWT;
container may refuse to load the GWT
jar as it contains the javax.servlet
package;
in most cases this will
likely deviate classpaths across your
IDE's debugger and the really
executing VM.
Link to the jar in question (just so you see the same thing after unzipping as I do, if you don't believe that GWT contains servlet API classes in the same jar):
http://repo1.maven.org/maven2/com/google/gwt/gwt-user/1.7.0/gwt-user-1.7.0.jar
You shouldn't be including gwt-dev.jar or gwt-user.jar in your war file. You only need gwt-servlet.jar in your war, and that too only if you are using RPC. If you notice, gwt-servlet.jar (ironically) does not contain any of the servlet classes.
gwt-dev.jar contains the compilers and linkers. Your code will never need this to compile.
gwt-user.jar contains the gwt framework that ultimately gets translated to javascript. You only need this during development mode.
gwt-servlet.jar contains the server side code that is needed if you use RPC framework. This is the only jar that should be present in your war file.
The reason the classes are in the package is to provide a full working solution for users who only use the gwt-user file in development. Without it GWT RPC wouldn't compile. This is/was the general view of the GWT team as can be found in this lively discussion on the GWT issue tracker: http://code.google.com/p/google-web-toolkit/issues/detail?id=3851
However, GWT 1.7 also contains the javax source files, which can cause additional problems. For example for maven and probably also for the points you mention. This was addressed in the GWT issue and in later version of GWT the javax source files have been removed from the gwt-user jar file.
For deployment you should use the gwt-servlet jar, which doesn't contain the javax classes or any other third party libraries. In the past several it could happen GWT files designed for client side use also used on the server side were missing from the gwt-servlet jar file. Losts of these issues have been addressed and classes were added to the servlet jar file. If you still find a GWT class you need is missing from the gwt-servlet you should file an issue report. In your case, assuming you're using 1.7, it might mean to upgrade to a newer version of GWT.