I'm using AspectJ and the 'ajc' command line compiler. I specify aspectjrt.jar, aspectjtools.jar, and aspectjweaver.jar on the classpath ('-cp') during compilation, yet when I call the standard 'thisJoinPoint', an exception is thrown:
Compilation:
ajc -cp lib/aspectjrt.jar:lib/aspectjtools.jar:lib/aspectjweaver.jar -inpath work/src/ -outjar ./mynewjar.jar #work/source.lst
Code which causes exception:
before() : onCreateCall() {
System.out.println("[-] PC Info: " + thisJoinPoint.getSignature());
}
And the exception itself:
Could not find class 'org.aspectj.runtime.reflect.Factory', referenced from method com.test.WooAspects.ajc$preClinit
Of course, I've tried specifying the import with the following, but no luck:
import org.aspectj.runtime.reflect.Factory;
import org.aspectj.runtime.reflect.*;
Any ideas?
When compiling your code, if it references types in a separate library, that library (possibly packaged as a .jar) needs to be available on the compilation classpath (javac or ajc in this case).
When running your code, if it references types in a separate library, that library needs to be available on the runtime classpath (java or the alternative for aspectj).
Note that an import statement is unrelated to the classpath. All an import statement does is allow you to use a type's or member's short name instead of its fully qualified name.
The following things seem to be a little odd at first glance:
It looks as if you think that -inpath work/src actually is meant to include source files, but the inpath is actually meant to include class files. What you probably want is -sourceroots work/src.
Then you seem to use an argument file named work/source.lst which you have not shown us, so we do not know what is in there - maybe more command line switches, maybe more source files. I have no idea.
On your ajc classpath there are all three AspectJ libraries, but usually you only need aspetcjrt.jar. The other two are only needed for load-time weaving [LTW] (aspectjtools.jar) or if you want to use the AspectJ compiler and a few other tools during runtime (aspectjweaver.jar).
For a simple project in which Java and AspectJ code are in the same source directory, the following works for me (inserting line breaks for better readability, but it is all one line on the console):
ajc
-1.7
-cp lib/aspectjrt.jar
-sourceroots src
-outjar my.jar
Then you run the aspect-enhanced JAR like this (again one line on the console):
java
-cp lib/aspectjrt.jar;my.jar
de.scrum_master.app.Application
I.e. during runtime you also just need the runtime JAR on your classpath.
Maybe you want to use a build tool like Maven managing your dependencies and the build process. You can also use plugins like Maven Shade or One-JAR in order to produce a single über-JAR containing both the compiled Java + AspectJ code and the AspectJ runtime. Then you do not have any problems with classpaths during runtime, you just call
java -jar my_uber.jar
Update: You may want to read the ajc documentation for more info.
Related
I have a set of ruby files where I have some string of type:
#something = [Whatever.new('1rabbit'),
Whatever.new('2rabbit'),
Whatever.new('3rabbit')]
I would like to parse out this information from the ruby file during compilation phase (javac run with maven - but i think it is no difference how javac is run), and create a .class enum of type:
public enum Something {
1RABBIT,
2RABBIT,
3RABBIT
}
and store it into the target folder. Then, I can use this enum whatever I want (after this initial compilation). I looked into AnnotationProcessors, and bytecode generation, but the first requires annotations, and the second is done during runtime. And I cannot find out how to do it properly.
What is the correct tool to do this, and how?
mavens life cycle has a generate sources phase. There you cold use the exec-maven-plugin to run a script generating the enums.
I'm trying to look under the hood about java compilation. So I put my IDE away and started using MS-DOS command-line...
I created a simple project, as described in the tree below :
SampleApp
|____**src**
|_____pack
|______Sample.java
|____**classes**
This is the Sample.java source code :
public class Sample
{
private String s = new String("Hello, world");
public Sample(){
System.out.println(s);
}
}
I just want to compile this class, so I used the javac command :
prompt\SampleApp\src>javac -d ..\classes -sourcepath . pack\Sample.java
All works fine, but i didn't expect that because I deleted my CLASSPATH environment variable before compiling my Sample.java file. So I was expecting a compiler error due to the fact that the compiler would not be able to find the java.lang.String class file.
I read this article http://www.ibm.com/developerworks/java/library/j-classpath-windows/ which helped me understand many things. The article author says that the default classpath is the current working directory. But I don't understand why my source code compile without error. Could someone explain this to me?
So I was expecting a compiling error due to the fact that the compiler would not be able to find the java.lang.String class file.
The short answer is that the compiler knows where to find all of the standard Java SE library classes without you telling it.
The longer answer is that String class is being found on the bootclasspath. This is implicitly set by the javac command to refer to the relevant JARs in the JDK installation. The javac command searches the bootclasspath before it looks for stuff on the regular classpath.
The classpath variable doesn't do what you think. To cite the oracle documentation:
The CLASSPATH variable is one way to tell applications, including the
JDK tools, where to look for user classes. (Classes that are part of
the JRE, JDK platform, and extensions should be defined through other
means, such as the bootstrap class path or the extensions directory.)
Source: http://docs.oracle.com/javase/tutorial/essential/environment/paths.html
Basically since java.lang.* is part of the platform and delivered with the JDK/JRE, the compiler doesn't have to be told by you where to look for them.
Given the following package structure:
| com.java.package
| A.java
| B.java
And the following code in B.java
package com.java.package
public class B {
private final A aObject = new A();
public void foo() {
aObject.foo();
}
}
Is is possible to include the following import line?
import com.java.package.A;
Rationale: I am writing scripts to parse file dependencies for my build system using import statements, and when dependencies are intra-package (within the same package), Android Studio (IntelliJ) will "optimize out" my import statements and remove them from the file.
Is there a way to force the IDE to keep my intra-package import statements?
As long as you never optimize imports, then it'll probably stay. There is a setting somewhere (varies by version) that allows you to specify how many imports of the same package before it optimizes to '*', you'll want to make that a huge number.
Ultimately, I expect IJ to optimize it away somewhere when you don't expect. Even though it does seem to compile, it looks/feels wrong and someone else unaware of your external dependency is going to chomp it.
Better solution is to make your scripts smart enough to recognize intra-package classes as all dependencies - because implicitly they are - and just simply the problem. What you've proposed doesn't sound like a workable solution
One answer is to skip trying to parse Java for imports and use the jdeps command which is part of the JDK. jdeps works on .class files so it will work on java and kotlin (and Scala, etc). I'm reviewing the emerge-vis app, and it has the same problem with same-package imports.
The jdeps command shows the package-level or class-level dependencies of Java class files. The input class can be a path name to a .class file, a directory, a JAR file, or it can be a fully qualified class name to analyze all class files. The options determine the output. By default, jdeps outputs the dependencies to the system output. It can generate the dependencies in DOT language (see the -dotoutput option).
I'd like to do some import of my own classes for use inside DSLD script, but DSLD compilation does not seem to use project's classpath - import statements break the compilation, and Class.forName throws class not found exception.
Is there a way to put custom jars on DSLD classpath, so I can use my own classes inside conribution blocks?
I am using Eclipse 3.7 and latest groovy plugin (2.6.0)
You can just pass a string with the fully qualified class name and as long as its on the projects classpath where the DSLD is being evaluated then it will work. This is described here groovy-eclipse DSLDs
Some subtleties about java.lang.Class references
Even though the DSLD script is being edited in the context of your
project, the script is actually loaded by Groovy-Eclipse. And so, the
runtime classpath of the script corresponds to Groovy-Eclipse's
classpath, rather than the classpath of your project.
Consequently, you cannot reference class objects for types defined in
your project. However, you can reference class objects that are
available to Groovy-Eclipse. This might be confusing since the
compiler will not show compile errors when types defined in your
project are referenced as class objects, but it will show compile
errors when Groovy-Eclipse types are referenced. This is because the
Groovy-Eclipse compiler works off of the project's classpath. It is
not yet aware that DSLD files will be run with a different classpath.
More specifically:
Instead of referencing the class MyLocalType directly, you can
reference it as a String "com.mycompany.MyLocalType" Standard JDK,
GDK, and all types defined in groovy-all are available directly in
your DSLD and will show compile errors. It is possible to reference
types in packages beginning with org.eclipse.jdt. and
org.codehaus.groovy.eclipse. if all references are fully qualified.
However, this is not recommended unless you really know what you are
doing.
I don't know much about the DSLD stuff, but it looks like Groovy might have it's own means of doing that.
Greetings,
I'm playing around with mahout, I've written a basic java class which imports some of the libraries. It seems my classpath is correct when compiling, I get no errors or complaints at all.
However when I run the compiled class I get an exception saying...
Exception in thread "main" java.lang.NoClassDefFoundError: Test
Caused by: java.lang.ClassNotFoundException: Test
My guess is that . is not on your classpath. For example, you might be compiling with:
javac -cp foo.jar:bar.jar Test.java
but then to run the code you'd need
java -cp foo.jar:bar.jar:. Test
The code that you're compiling doesn't need to be on the classpath as you're providing the code (so there's nothing to find) - that's why it manages to compile but not run.
That's only a guess, of course - if you could post the commands you're using to compile and run the code, that would help.
I'm now getting an error saying java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
You're missing slf4j-api.jar on your class path. With SLF4J, you always need slf4j-api.jar and another jar to bind a logging framework. And actually, if you don't care about logging, use slf4j-nop.jar instead of slf4j-log12.jar.
Update: Mahout seems to be available in Maven central repository so using Maven could ease the class path setup process. And if you're not into learning Maven, consider using MOP which is a command line launcher to run Java stuff that can transparently download Maven artifacts and their dependencies and setup your classpath.
Compile time classpath sounds right; runtime classpath is wrong.
From the javadocs for that class:
Thrown if the Java Virtual Machine or
a ClassLoader instance tries to load
in the definition of a class (as part
of a normal method call or as part of
creating a new instance using the new
expression) and no definition of the
class could be found.
The searched-for class definition
existed when the currently executing
class was compiled, but the definition
can no longer be found.
Do you see a Test.class file in the current directory? Maybe you compiled it to another path by mistake.
If you are using Mahout, be aware that after you build it with Maven, it will generate "*.job" files in the target/ directory, which contain all dependencies packaged together. It is just a .jar file.