I got a project with lots of dependencies and somewhere in my code I'm implementing a class, like this:
public class MyApp extends org.some.BaseClass
Problem is, there are multiple jars in the dependencies providing the base class org.some.BaseClass, some of them containing specific abstract methods that I need to implement, others don't. Obviously, the compiler wants to use one of those base classes that I don't want to implement, and it fails with this:
[ERROR] MyApp is not abstract and does not override abstract method getSome() in org.some.BaseClass
Now, from here: Find where java class is loaded from I learned about the jvm opt -verbose:class which lists all the classes that are being loaded and where it loads them from. This seems to be really nice for analyzation purposes. However, I guess since the compiler is still at work at that time and the classes have not yet been loaded fully, the source of org.some.BaseClass is not printed in the output. The compiler just fails and doesn't mention any details.
So, how can I find out what class is being compiled against at compile time? Is there another jvm flag that prints the same infos as verbose:class for files with compilation errors?
Update:
Solved by adding -verbose to the javac args. Turned out the wrong class came from a shaded jar that directly included all the classes from its dependencies. The IDE was unable to tell me about this, because that jar was also part of the project as a module.
From the javac manual:
-verbose - Verbose output. This includes information about each class loaded and each source file compiled.
Related
I've been using Eclipse for a while and I'm having trouble understanding what's going on with my first project in IntelliJ. I've read the documentation, and searched other questions, but I still can't seem to grasp it. I think there is something wrong with my project structure. This is what my structure currently looks like;
I'm trying to run the JavaForLoop class, but whenever I do, compilation fails because I have errors in the StringMethods class of the strings package. My question is why would that prevent compilation if the two classes are in separate packages? Neither class uses the other, and they both have the appropriate package declaration statements. With a similar structure in Eclipse, this would work. Should I be using a different project structure?
By default IDEA adds Build Configuration which is executed before launch and includes following steps (taken from here):
Compiling source code in the source path of a module and placing results to the output path.
Compiling source code in the test path of a module and placing results to the test output path.
Creating copies of the resource files in the output path.
Reporting problems in the Messages tool window.
check if it's your case in Edit Configuration screen and if so, remove it.
To use a class from a different package you must declare a import statement to the class.
In your JavaForLoop.java add the import before the class statement (and after package declaration where its the case)
//package ...
import strings.StringMethods;
//public class JavaForLoop { and the rest of the code
Intellij uses regular javac, which will fail to compile if you have errors anywhere in the code.
Eclipse has it's own compiler, that allows to compile and even run code that has compilation errors, causing a runtime exception if any part of the code that has errors is run. This allows you to run parts of the code that work even if other pieces of code are failing.
The simple solution is to resolve your compilation errors. You can also use the eclipse compiler with Intellij, but I've never done this so I can't comment on how well it works.
I would like to get deeper understanding on how Java deals with different versions of Classes/Packages/etc., but couldn't find any resources or at least the best way to google for it. The problem is as follows.
Imagine we have some external package com.external.package that contains a definition of SomeInterface.
Now I write a java class MyClass that implements SomeInterface, and using com.external.package v1.0.0. Next I package a (lean) jar containing MyClass.
Now I plug this jar in another program that is looking for implementations of SomeInterface, but in it's dependencies, it is using com.external.package v2.0.0.
Is the reason I get Failed to find any class that implements SomeInterface that versions of SomeInterface don't match in the program and in the jar that contains a class extending it?
Basically the question I would like to find an answer for is what info do jars store regarding external dependencies? Does it store the exact versions of them and if they don't match at the runtime it complains? But why does it even allow running the program with references to same dependency, but different versions?
Is the reason I get Failed to find any class that implements SomeInterface that versions of SomeInterface don't match in the program and in the jar that contains a class extending it?
There is no "versioning" happening here. Simply, the error states no such class exists on the classpath. For example, you didn't put a -cp in your java command to add that extra JAR/class file.
Other reasons this could happen is that an API marks a class as deprecated in v1, then decides to remove it from v2. In which case, you best try to compile and test your code against the proper library versions before you package your own code. If you made an uber JAR, the classes should get shaded, and you probably wouldn't have missing classes.
Maven projects do have the concept of transitive, versioned dependencies, but you've not said anything about that
Seeing that the original question has found an answer already, it seems somewhat relevant to mention that Java Packages and JARs could be used for specifying package version information as discussed in the following documentation:
https://docs.oracle.com/javase/8/docs/technotes/guides/versioning/spec/versioning2.html#wp89936
Also, the Oracle Java Tutorials discuss them and further concepts around deployment of programs as JAR Files as documented here:
https://docs.oracle.com/javase/tutorial/deployment/jar/index.html
To create and load a class at runtime, I first read its content from the database, create a new SimpleJavaFileObject and finally compile it at runtime by passing it to a CompilationTask.
The point is that this new file may refer to other files (directly imported or "indirectly" via de.package.*) that are also stored in the db and not available as classes or sourcecode-files.
public class Test1 {
public de.otherpackage.Test2 reply() {
return null;
}
}
Like Test1 I would have to create and compile Test2 a step ahead, because there are no JavaFileObjects or classes to feed the compiler with.
So: How do I get a list of all sources a compiler needs to compile one class?
It would be enough to know that Test1 needs Test2. I first tried it by passing a Processor to the CompilationTask. I checked all attributes in the Trees but didnt find anything usefull or complete. If a class is imported using * on a package there is no way to get a full qualified name... at least not for me :-/
Any ideas? Maybe there are better ways to parse javasources?
Thanks for helping :-)
If you are asking if there is a way to do this before you compile the class, then the answer is "No there isn't". The source code, and the source code alone determines the direct dependencies. And you need to compile the source code in order to extract them.
If you are asking if there is a way to extract the dependencies while or after compiling then there are a few alternatives:
The javac command has a -verbose option that causes it to list each class loaded, and each file compiled.
If you use the standard compiler APIs, it provides hooks for loading dependent classes and locating source files. You could use those to track what is going on.
You can get most of this information from the bytecode files themselves. There are a couple of caveats though:
If the code is compiled with -g:none there won't be source filenames in the ".class" files.
You can determine the dependencies, by compilation times are not recorded ... unless you can infer them from file timestamps.
A dependency on a compile-time constant declared in another class is fully resolved (and inlined) at compile time ... and won't have any trace in the generated ".class" file.
But note that you generally don't need to do this to compile a class. If the compiler finds that it needs to load or compile a dependent class, it does it automatically. At least, that is how javac behaves by default.
I'm trying IntelliJ IDEA after many years as an Eclipse user. At the same time, I'm working on a project that I've inherited with many dependencies.
One class will not compile, because IDEA claims that a method in another class does not exist. I can see the method in its source. Control-clicking on the class name in the IDEA editor takes me to the source that looks OK.
My hypothesis is that the compiler isn't using the class compiled from the source within the project, but a class with the same name, somewhere among my dozens of library jars.
How can I find out where IDEA's compiler is finding the clashing class?
CTRL-N and entering the class name should show you all of the matching classes from across the classpath, and which directory/JAR they're in. If there's a clash, you should have duplicates in that list.
Another possibility is that the source you have for the referenced class doesn't match the compiled version of that class.
I am writing an eclipse plugin to support the Frege programming language.
I use the IMP meta tooling platform and Eclipse Indigo (3.7). The run time environment is Java 1.7.
The plugin uses the same code as the batch compiler for token parsing, syntax analysis, etc. However, I noticed differing behavior when run from the eclipse plugin and traced it down to the following method that reads a class file of a previously compiled module to get meta-information which is stored there in form of java annotations:
public static MD.Operator[] getOperators(ClassLoader loader, String pack)
throws ClassNotFoundException {
Class<?> cl = null;
cl = loader.loadClass(pack);
MD.FregePackage os = cl.getAnnotation(MD.FregePackage.class);
if (os == null) return null; // <-- no annotation present
return os.ops();
}
Note that the code creates its own instance of an URLClassLoader, which is passed as argument. If I do not set the class path correctly, the getOperators method correctly throws a ClassNotFoundException, therefore I think I can be sure that it loads the class.
A trace message tells me that the class loader is built with the following path (which is just the classpath by default):
mkClassLoader:[C:\opt\eclipse\plugins\org.eclipse.equinox.launcher_1.2.0.v20110502.jar, X:\dev\frege\build]
Because a class file not created by the frege compiler cannot normally have the MD.FregePackage annotation this usually indicates that the user tried to import a plain java class, and indeed I get the following message in the plugin:
X:/dev/runtime-EclipseApplication/TestJFrege/src/Neu.fr:1: `frege.prelude.Base` is not a frege package
Yet, from the command line I can compile this just fine. I included this here as proof that the annotations in question can indeed be loaded from the same location:
X:\dev\frege>java -cp ./build frege.compiler.Main X:/dev/runtimeEclipseApplication/TestJFrege/src/Neu.fr
mkClassLoader: [./build]
running: javac -cp ./build -d . -encoding UTF-8 ./Neu.java
Resuming the facts:
The code that is supposed to load the annotations works fine when the compiler is invoked via command line interface.
The code that is supposed to load the annotations does not know whether it is invoked from the plugin or the command line. In fact, the plugin didn't even exist until last week, while the command line interface used to work fine for months.
The annotations have, of course, RetentionPolicy.RUNTIME otherwise the command line compilation would not recognize them either. But it proovably does.
So the only conclusion I can draw is that Class.getAnnotation() somehow is not working correctly. This is very unfortunate, as this effectively destroys basic functionality I need for the module system.
If this matters anyhow: the Frege compiler code the plugin uses is itself written in Frege and the frege.prelude.Base class mentioned above is a basic library that is needed by every module, hence it must already have been loaded on activation of the plugin, though of course with a different class loader.
Does anybody have similar experiences? Is it possible to solve this and how? Any suggestions how to circumvent this are welcome.
Was the MD.FregePackage class loaded by the classloader used in your method? Possibly try loading that one first, since two classes aren't equal() if they were loaded by different class loaders. That could explain why it isn't being found.