Superclass of a Java class in separate jar file showing as Object - java

I have a class called Passthru, which extends a class called Component, which is held in a jar file. At run time, I want to load Passthru (using URLClassLoader with one or more jar files, plus optionally a local directory), and then test the superclass against a few possibilities, of which one is Component. This works great if both Passthru and Component are in the same jar file, even if different packages, but if Passthru is in a local directory (with Component in the jar file, as before), doing getSuperClass on Passthru returns Object. I know Object is in Passthru's parent tree, but in this case I don't seem to be able to find out Passthru's direct parent. I suppose I could go to Passthru's source and scan to find the superclass, but there should be a simpler way...?!
I also noted that in both cases Passthru is loaded with my URLClassLoader, but when Passthru is in the local directory, its parent's loader shows as the "primordial" loader (null) - don't know if this is relevant...
Solved!! It was sort of a dumb question: it turned out that the source code in the directory was back level, and didn't match the code in the jar file. Also, I hadn't added the directory code as an Eclipse project, so apparently Eclipse compiled this code but didn't give me any error indications, so I didn't see the compile errors "behind the scenes". So when I worked purely in the jar file, everything worked, but when I went to the directory, compile errors prevented the classes there from picking up the Component class. Thanks to the people who responded to my question - sorry if I wasted your time!

Related

Determine loader jar of a dynamically loaded jar

How do I determine the name of the jar that is dynamically loading my jar? Is it possible? I have attempted many variants using ClassLoader but with no success.
Thanks in advance.
Let me explain why I need the name of the "loader jar". In our container we have the following lines:
URLClassLoader classLoader = new URLClassLoader(new URL[] { artifact.getFile().toURI().toURL() });
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, artifact.getArtifact().getFile().toURI().toURL());
Class<?> processorClass = classLoader.loadClass(className);
Object processorClassInstance = processorClass.newInstance();
When the loaded class is instantiated, newInstance above, it's properties files is external to the jar the class resides. The configuration files are in a directory named after the container jar that contains the class that executed the lines of code above. So, if the deployed container jar is called RedcapTDP.jar the configuration files are in "C:...\RedcapTDP". When the RedcapTDP.jar is deployed it dynamically loads the configured maven artifact which in turn will read it's configuration file from the RedcapTDP directory.
I hope that makes it clear!
How do I determine the name of the jar that is dynamically loading my jar? Is it possible?
Taking you literally, no, it is clearly impossible. In fact, it doesn't even make sense. Java does not "load" Jars at all, though it may load one or more classes contained within a jar. When it does so, it is the VM loading the class, not any jar loading it.
Interpreting you a bit more liberally, perhaps you are asking "how do I determine the class whose dependency on one of the classes in my jar is causing my class to be loaded, and how do I determine from which jar file that other class was loaded?" Unless your control extends beyond the classes in your jar, however, this is again impossible.
Class loading is a separate step preceding class initialization, and class initialization is the first point at which there is any opportunity to execute any code contained in your class. Thus, class loading is no longer ongoing when your classes first get a chance to inquire about anything. Moreover, classes are not necessarily loaded from jars at all, and in any event, they do not carry information about the source from which they were loaded.
I could perhaps go further afield with speculations about what you may mean to ask, but I don't see any interpretation of the question that affords an answer different from "no, it is not possible."
JARs don't load JARs. A jar file is just a meaningless container that helps holding class files and other resources together. Classes are loaded by a class loader(s) from a class path provided to the jvm. What you're trying to do is not possible. Maybe you can explain what you're trying to achieve and perhaps there is a better way to do it.

Class file creation concepts

I tried a strange experiment.
I created a project in Eclipse. I created Abc.java which has a main method which prints "Hello" to output.
I then built the project using eclipse. A class file named Abc.class was created. I copied that class file to some random location. Then , I navigated to the class file and used the following command to execute it.
java Abc
It printed "Hello" on the console. So far so well. I assume for a simple sysout there are no dependencies a JVM needs to resolve.
Next I created a very complex program in my eclipse for which I had to include 15 different jars(ex slf4j and apache-commons). After building the program in eclipse, I just copied its class files to a different location(not the JARS).
The main method which does all the complex coding was still in Abc.
I hit the command again(this time I followed package structure so I had to call a slightly different command).
java com.great.Abc
I was under the impression that since I hadn't added any jars to classpath in the java command, this code would break down miserably(remember it had a lot of dependencies).
However, its working absolutely fine.
Can someone please explain why?
(Half hour later :|)
Meanwhile I tried another experiment, and this amazes me even more. I mailed all the class files generated through eclipse to a different computer (note that I did not mail the jar files, only the class files generated by eclipse).
And I ran the program over there, hoping that it would break this time.
And guess what, it runs perfectly. Any inputs?
Are the jars required only at compile time?
How would I ensure that the jars I use are needed at runtime while creating a program?
Please explain calmly no matter how stupid the questions seem. :)
In Java, code dependencies are established between classes so when you create a class which just prints a message, your eclipse project setup has no relevance as long as your class is not using any class from the fancy eclipse setup.
Even if your class is referring to other classes it might happen that these classes are not loaded at runtime when the class is not really using them.
Even if you launch a Java program from a jar file which has dependencies to other jar files declared in its manifest, the standard Java launcher will ignore the absence of one or more of these jar files silently and during the program execution it will report failures only if required classes from these missing jar were tried to load.
One case were it is guaranteed that your program will break early is when its superclass is not present at runtime.
The Jar files aside, I actually find it strange enough that it even loaded your Abc class itself, since the JVM would look for com.great.Abc only in a com/great subdirectory of your classpath. I suspect that you, somehow, have some implicit classpath set in your environment or something, which points back to your Eclipse environment, and that the JVM found it there.
To verify this being or not being the case, you can run Java with the -verbose:class option, to make it tell you where it loads classes from:
java -verbose:class com.great.Abc
Eclipse uses the Absolute path to your included jar files.
Even when you move your main class it still works fine

Eclipse: The type VertexNotFoundException could not be resolved. It is indirectly referenced from required .class files

I'm working on some code for a class project. We're given a .jar file with some classes we need to use. In using those classes, I encountered quite an error. One of the classes, a directional graph, has a method for adding an edge between two nodes in a graph. That method throws a VertexNotFoundException, defined in one of the .class files in the jar we were given. Whenever I try to use that method, I get the error listed in the title: The type VertexNotFoundException could not be resolved. It is indirectly referenced from required .class files. I added the jar to my project by going through Build Path->Configure Build Path->Libraries->Add External Jar and selecting this jar. The directed graph class, also found in the jar, works fine, yet VertexNotFoundException does not.
Note that I do not directly reference VertexNotFoundException in my code, but I use code which references it.
A little bit (the first two pages) of googling revealed that this error message likes to pop up when people don't include certain Apache jars in their Apache project, yet I am not using Apache for this project and have no need to do any server things at all. I also found that this error likes to happen with some classes from the Java runtime itself, but that was supposedly fixed in Eclipse 3.4.
-1 because this didn't work, but I use www.findjar.com Type in the class and it will (most of the time) list JAR that contain it. I tried it with your class, which the site recognizes, but it didn't know of any JAR.

JAVA ClassLoad same class name

Yesterday i thought one question ,below is the detail:
I have 3 JAR files, a.jar, b.jar ,c.jar . both these jars files have a class named com.test.Test ,and sayHello() was defined in this class.
I create a web application, i reference a.jar,b.jar,c.jar . And in main method, i involve sayHello(); .at this time, which com.test.Test will be load?
the result is a.jar.
any body tell me the reason ?? thanks in advance!!!
That is what java language specification says. It loads what ever the class first occurs in classpath and ignores other.
Instead of focusing on which one will be loaded, realize that the stuff within the JAR files probably need their com.test.Test class instead of someone else's com.test.Test to work properly. That means for a functional system you'll have to make a way that a.jar finds a.jar's com.test.Test instead of the one in b.jar. The same goes for b.jar finding it's classes in preference to a.jar's.
The only way to do this is to use a framework which adds name spacing beyond the java package mechanism. This is typically done with multiple classloaders, often one for each JAR file. You can write such a thing yourself (Tomcat did), where you need to specify the rules for cross-loader discovery, or use something akin to a OSGi framework.
Whichever Jar File comes first in your classpath will be used..
You can modify your CLASSPATH environment variable to the path of your Jar file
Suppose you modify it as below: -
set CLASSPATH = %CLASSPATH%;.;a.jar;b.jar
then a.jar will be used..
You can also modify it by: -
set CLASSPATH = %CLASSPATH%;.;b.jar;a.jar
In this case, b.jar will be used..
These commands you need to run from your Command Line..
** NOTE: - If you are using any IDE, then they don't use System Classpath.. You need to set different classpath for the IDE you are using..
If you are using an IDE, such as eclipse, you can modify your classpath on the properties of the project, then go to Build Path, and then you have the Order and Export tab where you can move up and down the jars. The one of the top will be the first taken by your application.
This you can also do manually by editing the file called "classpath" which is on your project and move to the top the jar you want your application to use first.

Java packages and compilation (why, not how)

I'm working on some Java code in eclipse. Code is contained in a single class called Adder, which in Eclipse is in the package org.processing. The first thing in the class file is the line
package org.processing
Q1) What, exactly is this line doing? Why is there, what's it's role.
The code runs fine in eclipse, however, when I move into the workspace if I go to the src/org/processing/ folder in src, compile with javac Adder.class when I try and run using java Adder I get the following error
java.lang.NoClassDefFoundError: Adder (wrong name: org/processing/Adder)
On the other hand, if I compile from src using
javac org/processing/Adder.java
and I can run it from src using java org.processing.Adder but STILL not from within the processing directory.
Q2) Does this mean that compilation is always relative to directory structure?
Finally, if I remove the package org.processing line from the start are the .class file I can compile and run from within the .class file's directory.
Q3) Why is all this the way it is? I can fully understand enforcing a directory structure for code development, but once you're in bytecode this seems a bit over the top, because now I can (apparently) only run the bytecode from one director (src) using java org.processing.Adder. Now, I'm sure I'm missing the point here, so if someone could point out what it is, that would be great.
The compiler has to be able to find related source code files when compiling. This is why the package and directory structure must agree for source code. Similarly, the JVM must be able to find referenced .class files. So the same directory structure is required at runtime. It's no more complex than that.
Q1) The issue here is that once you got into the folders that represent your package hierarchy, you set that as the working directory. It's gonna look inside of org/processing/Adder for the path org/processing/Adder (essentially looking from the root for org/processing/Adder/org/processing/Adder). You need to call it from the root with the full path. The purpose of packages is A: to organize related classes into groups. And B: Along with A, classes in package Foo.bar can't view private classes in other packages, as they are like internal classes for that package, only the package they're in can use them
Q2) Yes
Q3) The paths are used as a basic structure for the JVM to know where exactly the class files (each containing their bytecode) are. If you change where you call it from, your basically trying to change the location for the JVM to look for the class files, but their true location hasn't changed.
The short answer - Packages help keep your project structure well-organized, allow you to reuse names (try having two classes named Account), and are a general convention for very large projects. They're nothing more than folder structures, but why they're used can burn beginners pretty badly. Funnily enough, with a project less than 5 classes, you probably won't need it.
What, exactly is this line doing? Why is there, what's it's role.
The line
package org.processing
is telling Java that this class file lives in a folder called /org/processing. This allows you to have a class which is fully defined as org.processing.Processor here, and in another folder - let's say /org/account/processing, you can have a class that's fully defined as org.account.processing.Processor. Yes, both use the same name, but they won't collide - they're in different packages. If you do decide to use them in the same class, you would have to be explicit about which one you want to use, either through the use of either import statements or the fully qualified object name.
Does this mean that compilation is always relative to directory structure?
Yes. Java and most other languages have a concept known as a classpath. Anything on this classpath can be compiled and run, and by default, the current directory you're in is on the classpath for compilation and execution. To place other files on the classpath, you would have to use another command-line invocation to your compilation:
javac -sourcepath /path/to/source MainClass.java
...and this would compile everything in your source path to your current directory, neatly organized in the folder structure specified by your package statements.
To run them, as you've already established, you would need to include the compiled source in your classpath, and then execute via the fully qualified object name:
java -cp /path/to/source org.main.MainClass
Why is all this the way it is?
Like I said before, this is mostly useful for very large projects, or projects that involve a lot of other classes and demand structure/organization, such as Android. It does a few things:
It keeps source organized in an easy-to-locate structure. You don't have objects scattered all over the place.
It keeps the scope of your objects clear. If I had a package named org.music.db, then it's pretty clear that I'm messing with objects that deal with the database and persistence. If I had a package named org.music.gui, then it's clear that this package deals with the presentation side. This can help when you want to create a new feature, or update/refactor an existing one; you can remember what it does, but you can't recall its name exactly.
It allows you to have objects with the same name. There is more than one type of Map out there, and if you're using projects that pull that in, you'd want to be able to specify which Map you get - again, accomplished through either imports or the fully qualified object name.
For Q1: The package declaration allows you to guarantee that your class will never be mistaken for another class with the same name. This is why most programmers put their company's name in the package; it's unlikely that there will be a conflict.
For Q2: There is a one-to-one correspondence between the package structure and the directory structure. The short of it is that directories and packages must be the same, excepting the package is usually rooted under a folder called src.
For Q3: Once it's compiled, the class files will probably be in the appropriate folders in a jar file. Your ant or maven tasks will build the jar file so you won't really have to bother with it beyond getting the ant task set up the first time.

Categories