I am facing one problem. I renamed javac.exe on my machine and noticed that ant javac task still works fine.
Does anybody know from where its getting javac.exe?
Actually, I believe, that by default Ant tries to execute the java compiler class directly with this code:
try {
Class c = Class.forName ("com.sun.tools.javac.Main");
Object compiler = c.newInstance ();
Method compile = c.getMethod ("compile",
new Class [] {(new String [] {}).getClass ()});
int result = ((Integer) compile.invoke
(compiler, new Object[] {cmd.getArguments()}))
.intValue ();
return (result == MODERN_COMPILER_SUCCESS);
} catch (Exception ex) {
if (ex instanceof BuildException) {
throw (BuildException) ex;
} else {
throw new BuildException("Error starting modern compiler",
ex, location);
}
}
The code came from here.
Which means that if the library tools.jar is on the current classpath of Ant, it will pickup the class and launch it. This results in the fact that javac.exe can be renamed to whatever you want, it will still work. So to answer your question, it actually executes none of any "javac.exe".
There are other implementations of the Javac task, but I think this is the default one for all compilers 1.3+
You could try starting here and check what is configured in global build.compiler property, it may be pointing somewhere else
Related
I'm using this code to set the macOS dock icon of my JavaFX app:
try {
// Sets macOS dock icon:
com.apple.eawt.Application.getApplication().setDockIconImage(SwingFXUtils.fromFXImage(appIcon, null));
} catch (Exception e) {
// Doesn’t work on Windows and Linux
}
I can't run the app on Windows because it throws the error "java: package com.apple.eawt does not exist"
How can I catch a "package x does not exist" error or check if it exists at runtime?
You could try to find out what your current OS is beforehand. There are basically two ways. Either System.getProperty("os.name") or SystemUtils.OS_NAME from Apache Commons Lang.
See also: https://www.baeldung.com/java-detect-os
You can't - it's a compiler error, you can't catch those at runtime. But the notion of 'can I run this code if the class is there, but not run it otherwise' - yeah you can do that, you just have to use reflection, which basically turns compile time stuff into runtime stuff:
public boolean trySetMacOsDockIcon(Image img) {
try {
Class<?> c = Class.forName("com.apple.eawt.Application");
Method m = c.getMethod("getApplication");
Object application = m.invoke(null);
m = application.getClass().getMethod("setDockIconImage", Image.class);
m.invoke(application, img);
return true;
} catch (Exception e) {
return false;
}
}
you may want to log those exceptions, at least until you tested this once or twice.
m.invoke(null) invokes the method; the first argument is the 'receiver' (the thing to the left of the dot); for static methods, there is no receiver and the parameter doesn't do anything. getApplication is static, so we pass null there. The second invoke line is an instance method on apple's Application class, so there we do need to pass in a value, namely, the application object we got by invoking getApplication. The second parameter there is simply the params for that method, so, we pass the image.
In my main program I am allowing users to create Java classes and storing them in a .java file within the package UserInputs. I am now looking for a way to instantiate the user created class within my main program and also running the public methods within the class.
Here is the code which gets executed when the user presses a JButton to finish creating their class.
public void actionPerformed(ActionEvent e) {
if(e.getSource() == inputButt.getButtons()){
try{
PrintWriter writer = new PrintWriter("C:/Users/human/Desktop/UserInputTest/src/UserInputs/UserCreatedClass.java", "UTF-8");
writer.println(textArea.getText());
writer.close();
}catch(Exception except){
except.printStackTrace();
}
}
}
You need to compile the file at runtime. Maybe this or this post here on SO helps you.
What the first link says is that you should use the Java 6 Compiler API. What you need to do is this:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, null, null, fileToCompile);
Where fileToCompile is the path to your file, in your case "C:/Users/human/Desktop/UserInputTest/src/UserInputs/UserCreatedClass.java". Then you can execute the code via Reflection.
I would be very carefully with letting people create and execute their own Java code, though. I don't know what you plan to do but if you are running this code on a server, I would not recommend doing such things. In case this application should run locally on the clients computer (so they can only harm themselves) this should not be a problem. Otherwise I would not let them program what they want.
You might also want to consider Groovy compiler which is almost fully compatible with Java syntax, more functional and has simpler API. Example from a Groovy page:
ClassLoader parent = getClass().getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);
Class groovyClass = loader.parseClass(new File("src/test/groovy/script/HelloWorld.groovy"));
// let's call some method on an instance
GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();
Object[] args = {};
groovyObject.invokeMethod("run", args);
I created a reasonably big web project on Eclipse (8 months of work). I've been using Eclipse build system until now. Now I'd like to go to Ant for a number of reasons (among them, be able to add certain pre WAR tasks, like js compression and other...). I discovered that Eclipse creates a build.xml file automatically, with all dependencies set up. The problem is that if I try to run it, it fails and gives this error:
type parameters of <TypeName>TypeName cannot be determined; no unique maximal instance exists for type variable TypeName with upper bounds TypeName,java.lang.Object
[javac] return dao.getItemByProperty(propertyName, val, objectClass);
it besically dies beacause of an error with generics.... usually it compiles fine on Eclipse (I know it is a different compiler...). How can I have javac work with this??
The method is:
#Override
#Transactional
public <TypeName> TypeName getItemByProperty(String propertyName,
Object val, Class objectClass) {
return dao.getItemByProperty(propertyName, val, objectClass);
}
and dao.getItem... is
#Override
public <TypeName> TypeName getItemByProperty(String propertyName,
Object val, Class objectClass) {
Session sess = sessionFactory.getCurrentSession();
Criteria criteria = sess.createCriteria(objectClass);
criteria.add(Expression.eq(propertyName, val));
#SuppressWarnings("unchecked")
List<TypeName> results = criteria.list();
if (results != null && results.size() != 0) {
TypeName res = results.get(0);
return res;
}
return null;
}
they are in two classes that respectively implement two interface, the first for a service, the second for a dao and they are used in Spring.
Why is this happening? Is Eclipse compiler so different from javac?
What version of Ant is actually being used, and which version of the compiler is being used? For a sanity check, try this at the command line where you are trying to run ant:
ant -v.
javac -v.
I ran into a similar situation once, where everything should work but didn't. Here Weblogic had an older version of both ant and javac than what I was trying to use, and these older version were being used instead of the ones I wanted. I ended up writing a script that explicitly set these variables in my PATH, and running the script before running the ant task.
I've been staring at this issue for hours now. Any help is appreciated.
I wrote code that uses the Jode decompiler from the "embedded jode jar file". I want to use this version because it is under the Lesser GNU Public License.
Decompiler d = new Decompiler();
try {
FileWriter fw = new FileWriter("c:\\jode.txt");
d.setClassPath("C:\\mycode");
ProgressListener p = new ProgressListener() {
public void updateProgress(double arg0, String arg1) {
System.out.println("inside of progress listener with arg0 = " +arg0+ " and arg1 = " +arg1);
}
};
d.decompile("Test.class" , fw, p);
} catch (Exception ex) {
ex.printStackTrace();
}
and I always get :
Exception in thread "main" java.lang.NoClassDefFoundError: Test.class
at jode.bytecode.ClassInfo.loadInfo(ClassInfo.java:620)
at jode.decompiler.ClassAnalyzer.<init>(ClassAnalyzer.java:86)
at jode.decompiler.ClassAnalyzer.<init>(ClassAnalyzer.java:123)
at jode.decompiler.Decompiler.decompile(Decompiler.java:191)
at testdecompiler.Main.main(Main.java:45)
If I use
jode.decompiler.Main.decompile(...)
things work - but I can't use this class file because it resides in the jode.jar that is only GPL.
I was able to reproduce the problem with all of the different binary versions of jode that are available from their web site. When I built a new version of jode using the mainline from svn, it worked fine. I also saw an entry in one of the jode forums where a user was complaining about the NoClassDefFound problem. His case sounded slightly different, but the jode developer suggested that he use the mainline from svn instead of the prebuild binary.
d.setClassPath("C:\\mycode");
This classpath looks awfully short to me.
This is a guess, as i don't fancy myself with decompiling classes, but i think that u should use
d.decompile("Test" , fw, p);
instead of what u are using now. This could be similar to
Class.forName("ClassName")
without the "class" suffix.
Update: My original assumption was wrong, and to bad, the original exception/ message is thrown away, as far a i can see. The code where JODE fails looks like this:
try {
DataInputStream input = new DataInputStream
(new BufferedInputStream
(classpath.getFile(name.replace('.', '/') + ".class")));
read(input, howMuch);
} catch (IOException ex) {
String message = ex.getMessage();
if ((howMuch & ~(FIELDS|METHODS|HIERARCHY
|INNERCLASSES|OUTERCLASSES)) != 0) {
throw new NoClassDefFoundError(name);
}
Since an IOException has to be thrown to get the NoClassDefFound, check anything regarding your IO subsytsem, e.g. the file.encoding. I guess you should patch JODE to get the detailed error message or debug to this point.
I have the following code:
// Test TODO remove
try {
System.out.println(System.getProperties().getProperty("java.class.path"));
this.getClass().getClassLoader().loadClass("mypackage.MyClass");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Now the output shows me, that the class is on the classpath, i.e.:
/...some/path.../workspace/project/target/test-classes:/rest/of/the/classpath
java.lang.ClassNotFoundException: mypackage.MyClass
...here be stacktrace...
I also made sure, that the class-file acutaly IS in the given location, i.e. this file exists:
/...some/path.../workspace/project/target/test-classes/mypackage/MyClass.class
Maybe the following is important: the shown code is executed in a javaagent attached to a jUnit test, that I start programtically (via Runtime.execute(...)) - so there is probably something beyond the obvious that can go wrong in the background... but still: if the classpath contains the folder with the class, how come it cannot be loaded?
The Java agent is loaded early in starting the JVM (for obvious reasons) and has its own "classpath", so it isn't actually loaded by the (historically named) system class loader. That is why you have a 'jarpath' as part of the command line argument.
SO you will need something like System.getSystemClassLoader, URLClassLoader.newInstance (with java.class.path) or Thread.getContextClassLoader depending upon your circumstances.
For all who are interested:
I have no idea what the problem was.
I fiddled a bit with it, and it turned out that the command string that was executed by Runtime.exec(...) worked well if executed in the shell.
I fiddled a bit more, but finally gave up searching for the "real" reason. Instead of
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(command);
I now use apache exec:
CommandLine commandLine = CommandLine.parse(command);
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(commandLine);
with the exact same command String, and all of a sudden it woks!
You assume that if the target bytecode remains at classpath corresponding class can be loaded by the current class's class loader. However, that is not the case if current class is loaded by tricky/buggy class loader.
I'd suggest to do the following:
Check the used class loader:
System.out.println(this.getClass().getClassLoader());
System.out.println(ClassLoader.getSystemClassLoader() == this.getClass().getClassLoader());
this.getClass().getClassLoader().loadClass("mypackage.MyClass");
Provide minimal but complete reproducible test-case that illustrates the problem