Where on the file system was my Java class loaded from? - java

I think this is a situation every Java programmer runs into if they do it long enough. You're doing some debugging and make a change to class. When you go to re-run the program, these changes don't seem to be picked up but rather the old class still seems to be running. You clean and rebuild everything, same issue. Sometimes, this can come down to a classpath issue, of the same class being on the classpath more than once, but there doesn't seem to be an easy way to figure out where the class being loaded is coming from...
Is there any way to find the file path for the class that was loaded? Preferable something that would work either if the class was loaded from a .class file or a .jar file. Any Ideas?

Simply run java using the standard command line switch"-verbose:class" (see the java documentation). This will print out each time a class is loaded and tell you where it's loaded from.

If you wanted to do it programmatically from inside the application, try:
URL loc = MyClass.class.getProtectionDomain().getCodeSource().getLocation();
(Note, getCodeSource() may return null, so don't actually do this all in one line :) )

public static URL getClassURL(Class klass) {
String name = klass.getName();
name = "/" + convertClassToPath(name);
URL url = klass.getResource(name);
return url;
}
public static String convertClassToPath(String className) {
String path = className.replaceAll("\\.", "/") + ".class";
return path;
}
Just stick this somewhere, and pass it the Class object for the class you want to find the definition of. It should work regardless of where it called from, since it calls getResource() on the class being searched for.
public static void main(String[] args) {
System.out.println(getClassURL(String.class));
}
Sample output:
jar:file:/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Classes/classes.jar!/java/lang/String.class

As the class needs to come from somewhere in the class path, I would recommend to simply print the class path and check if there's an older version of you class somewhere.

Related

Java changing method return without access to the class Class

I'm modifying someone else's code to implement a new functionality and I can't do it without changing the return of one of the functions. As I've said, this is not my code, so I can't change a single line of code.
The function itself is the following:
package me.Mohamad82.MineableGems.Core;
public class DropReader {
...
public DropReader() {}
public CustomDrop readCustomDrop(ConfigurationSection section, String mined, #Nullable String sectionNumber) {
...
}
}
And I'm trying to do something like this:
package com.rogermiranda1000.mineit;
public class DropReader extends me.Mohamad82.MineableGems.Core.DropReader {
public DropReader() {
super();
}
#Override
public CustomDrop readCustomDrop(ConfigurationSection section, String mined, #Nullable String sectionNumber) {
CustomDrop drop = super.readCustomDrop(section, mined, sectionNumber);
if (drop != null) {...}
return drop;
}
}
The problem is that I have no idea where to start. I can't change their code to call the other object, and I can't change the function call either.
The object is created every time (inside the functions that uses DropReader) so Reflection won't work, and searching I found something named Javassist but it won't work if the class is already loaded. I should be able to load by code before, but even with that I don't know if I'm approaching to the problem correctly, what do you think?
Edit: I'll try to explain better the situation. There's a class named Commands that runs the command new DropReader().readCustomDrop(section, mined, sectionNumber). The problem is that if section.getString("mine") != null I need to change the readCustomDrop return (I need to add an aditional property).
I can't change Commands's code, nor DropReader. Commands MUST get the modified object.
Edit2: It should work on both Java 8 and 17.
Probably the best way to do this is Java Instrumentation, but it was too complex for me so I did the following (assuming you have the .jar, and the .jar it's not already loaded):
Open the .jar as a Zip using ZipFile class
Send the .java to ClassFileToJavaSourceDecompiler (from JD-Core) and decompile it
Change the .java code
Compile the new code running javac with Runtime.getRuntime().exec (note: you'll probably need to add the dependencies using -classpath)
Add the compiled .java to the .jar

Import .jar libraries in VS Code

I need to use a .jar library, given by my teacher, to code for my Java class.
I am using VS Code, with the Java Extension Pack installed, for Java Project Management.
Can someone please explain me step by step how is it possible to import the .jar library, in order to use the classes defined by my teacher.
I have tried to copy the .jar in the lib folder and then add the reference, but it still did not work. I also know that I have to declare the classpath, but when I create the Java Project the .classpath file is not created automatically.
Thanks already!
First you should examine the classes in .jar file. Then you should load that class as,
Class<?> c1 = Class.forName("java.lang.String");
Then after you can use that class by calling that Class reference type variable.
See this example as well,
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// get the Class instance using forName method
Class c1 = Class.forName("java.lang.String");
System.out.print("Class represented by c1: "+ c1.toString());
} }
Try to understand the code and implement proper solution to your project.
Good Luck.

Error class not Found fixed but I don't understand why

The file "HelloDemo.java" path is "/test/hello/HelloDemo.java"
package test.hello;
public class HelloDemo {
public static void main(String[] args) {
System.out.print("Hello!!");
}
}
when I "run" it, an error occurred.
Building HelloDemo.java and running HelloDemo
Error: Could not find or load main class HelloDemo
Then, I changed the code.
//package test.hello;
public class HelloDemo {
public static void main(String[] args) {
System.out.print("Hello!!");
}
}
when I "Run" it, code success output.
Building HelloDemo.java and running HelloDemo
Hello!!
This is the screenshot about the "Run".
I fixed an error, but I don't konw why, I need help, Thank you!
If I want to keep the package uncomment, How to fix it?
That's because you probably changed the location of your file after running it once already. Hence, the running configuration should change to look for the new test.hello.HelloDemo class inside the built jar and not for HelloDemo anymore (which was probably in the default package, initially). What is your IDE?
Remark: This is not because you changed the location of your file that the classpath changed, and vice-versa.
On IntelliJ, you should do this: https://www.jetbrains.com/help/idea/creating-and-editing-run-debug-configurations.html
Create a package using your IDE and add your class to it. Package name will be appended to top automatically.
Reguardless of IDE, folder structure should match package structure, your problem could be here.
A class's name is actually the package plus the class name. You cannot run HelloDemo in your first case, because that is not the class name. The class name is test.hello.HelloDemo.
By commenting out the package, you've essentially renamed the class to HelloDemo, so it runs.
In addition, when running the class with main, you must be in the correct location. For instance, if the class is test.hello.HelloDemo, your folder structure will be /test/hello/HelloDemo.java.
You must be in / and run test.hello.HelloDemo from there.

Change name of a Class

Is it possible to change the name of a class retrieved using:Foo.class.getName() (or getSimpleName() or getCanonicalName()).
I know that those methods are part of java.lang.Class<T> the question itself is if there is a way to tell java.lang.Class<T> what is the name that I want it to display for my class.
I know that it "opens the door to tricky things" since that name is used by the reflection libraries to do "stuff" and bla bla bla. nevertheless I was wondering wether is posible to call Foo.class.getSimpleName() and get something like MyFoo.
All of this of course without string manipulation which is the last alternative I have.
Find the src.zip in your JDK. Extract java/lang/Class.java into some directory and modify getSimpleName() method. For example like this:
public String getSimpleName() {
return "MyName"; // return MyName for any class
}
Compile it normally with javac (you will get many warnings, ignore them). Remove all additional classes created like Class$1.class, leaving only java/lang/Class.class file. Put it into jar:
$ jar -c java >myclass.jar
Now prepend the bootstrap path with your new jar. For example, let's consider this test class:
public class Test {
public static void main(String[] args) {
System.out.println(Test.class.getSimpleName());
}
}
$ java Test
Test
$ java -Xbootclasspath/p:myclass.jar Test
MyName
I don't even want to explain how dangerous it is. Also according to the Oracle binary code license (supplemental term F) you cannot deploy your application this way.
You may try Powermock which according to their home page allows mocking final classes although it needs to use it's own class loader.
Other mocking frameworks that do not do byte code manipulation with custom class loaders such as Mockito and Easymock cannot work with classes that are final which java.lang.Class is.

Use resources of foreign maven modules?

I'm trying to use a resource from another module to import a file. My goal is to pass the filename by each custom class, and let the base class of another module fetch the file.
But I always get a Nullpointer Exception.
What am I doing wrong?
Module A:
src/main/java/foo/bar/MyBaseClass.java
src/main/resources/foo/bar/test.xml
Module B:
src/main/java/other/path/MyCustomClass extends MyBaseClass
classes:
abstract class MyBaseClass {
public static String TESTFILE = "foo/bar/test.xml";
getData(String filename) {
InputStream inputStream = MyBaseClass.class.getResourceAsStream(String filename); //NPE
}
}
class MyCustomClass extends MyBaseClass() {
doSomething() {
getData(TESTFILE);
}
}
/edit:
should I maybe use something like this?
super.getClass().getResourceAsStream(..)
It's very likely you should be using ClassLoader.getResourceAsStream()
e.g.
Thread.currentThread().getContextClassLoader().getResourceAsStream()
(probably safer, might work in different environments more correctly, i.e., where a special classloader is being used, Java EE?)
or at least
aClass.getClassLoader().getResourceAsStream()
this is how you should load resources on the classpath which may be in a different JAR (or classpath entry) than the given class you're calling getResourceXXX on.
If you're using a class that's in module B and you want to load resources from module A, you need to use ClassLoader.getResourceXXX.
So in Java you should generally use this approach (unless you care about restricting resource loading to a smaller area...)
Another thing to be careful about: pay attention to the need for a leading "/", always double-check the javadocs of whichever method you're using
see also: http://www.xyzws.com/servletfaq/what-is-different-between-classloadergetresourceasstream-and-classgetresourceasstream/21
The getResourcesAsStream() expects a name which is NOT a filename cause it's a resource name. Furthermore it looks like you are trying to access a resource from an other maven module. And not to forget you are trying to access the resource via a relative path which should be changed into an absolute resources path like /foo/bar/test.xml instead of foo/bar/test.xml.

Categories

Resources