How to get current path when program is loaded dynamically - java

I'm not able to give this question an apt title so apology for that.
I am making a modularised application. I load various jar files at runtime and invoke particular method of a particular class (of the jar file) at run time.
The jar file has some supported file. Now my jar file uses another application , lets say abc which is located in the same directory where i have kept the jar file. When i run the jar file then
new File(".").getAbsolutePath()
gives the correct path (this is where abc is located) and program runs fine. But when i load this jar file dynamically and invoke method using reflection above code gives the path of the parent program and abc is not found at that path.
Now my question is how do i find the path in which my jar file exists when i'm running my jar file's code using reflection.
Please let me know if you need more explanation.

Try something like this:
public static void main(String[] args) {
System.out.println(StringUtils.class.getResource("StringUtils.class"));
}
(Note: StringUtils is present on my classpath as a Maven dependency at the time) This gives me:
jar:file:/home/******/.m2/repository/org/apache/commons/commons-lang3/3.4/commons-lang3-3.4.jar!/org/apache/commons/lang3/StringUtils.class
Since the class is in a JAR file, it also gives me the location of the class file within the JAR.

Related

Java runs in eclipse and will compile, but wont execute on cmd, but still runs in eclipse. How can I get it to execute in cmd?

So I have a basic hello world set up in eclipse and I can compile it using cmd easily (I have set all the necessary paths), however when I then try to use the java command to execute the hello world, it always returns the same error:
Error: Could not find or load main class helloWorld
Caused by: java.lang.NoClassDefFoundError: net/codejava/helloWorld (wrong name: helloWorld)
This is the code used:
package net.codejava;
public class helloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
I am cd in the right directory (I think, I cd into the src directory and then into the package file stored in src) and am using Windows 10 with java 18.0.1 and JRE build 18.0.1+10-24
Any help would be greatly appreciated, as this is highly frustrating, when the code runs effortlessly on the eclipse console. Thanks.
Your file has a 'package' of net.codejava and a name of helloWorld, meaning, the full name of this class is net.codejava.helloWorld.
The java command, at least in the way you're using it, requires that you pass the full name, thus, you must run java net.codejava.helloWorld. Just java helloWorld simply isn't going to work.
But that's not all.
Java needs to then find the class file that contains the code for class net.codejava.helloWorld. It does this by first turning that full name into a path of sorts: net/codejava/helloWorld.class, and it will then scan each entry in the classpath for that. You can put directories and jar files on the classpath.
Thus, you have a directory on your system; let's call this directory X. X contains a directory named net, which contains a directory named codejava, which contains a file named helloWorld.class. If there is no such X (i.e. your class file is not in a dir named codejava for example), you're going to have to fix that by making these directories.
Then, X (and not the codejava dir!) needs to be on the classpath. Usually (it depends on how you configured things), 'the current dir' is by default on the classpath.
Given that your code is in, say, /home/PythonSux/workspace/learningjava/net/codejava/helloWorld.class, that means the dir that needs to be on the classpath is /home/PythonSux/workspace/learningjava. After all, if you, from there, look for net/codejava/helloWorld.class, you find the right file.
Therefore, either cd to that directory, or run java -cp /home/PythonSux/workspace/learningjava net.codejava.helloWorld
Note that this isn't usually how you actually run java apps. You either run them from your IDE, or you ask your build tool to run it, or you package your java app into a jar file and run that, etcetera.

Java: Reading images/files inside the compiled .jar throwing NullPointerException

I have a class that compiles a bunch of textures from a given folder into one big BufferedImage. It works perfectly when I run my program inside the IDE (Eclipse), but when I export it to a .jar, it throws a NullPointerException because it's not able to see the files inside the jar.
I think this has something to do with the File class, but I'm not sure.
The class's constructor takes a String path which represents the path to a folder inside the project's src folder. I use this line here to turn the partial path into a full path:
path = getFullPath(path);
The getFullPath method is just one line:
public String getFullPath(String path)
{
return Thread.currentThread().getContextClassLoader().getResource(path).getPath();
}
I then iterate through all files in the folder at path:
for(File f : new File(path).listFiles())
This works flawlessly in the IDE. For example, when I pass assets/textures/sky/ into the constructor as path, it successfully finds /C:/Users/MyName/eclipse-workspace/ProjectName/bin/assets/textures/sky/, then iterates through all the files in that folder.
However, when I export the project as a .jar and run it, it throws a NullPointerException when it gets to new File(path).lisFiles() because it can't find anything there. I've printed path to the console and the path is correct save for an !exclamation mark after the name of the .jar, which makes me think that the File class can't read .jars.
I'm aware of classes like ZipFile or JarFile that work differently, but I'm not familiar with them, and Google has not been helpful. Would anyone like to lend me a hand with this?

How do I access the resources directory for a calling program in Java

I have a library which is used by a program. This library loads a special directory in the resources folder.
in the library I have the method
public class DataRegistry{
public static File getSpecialDirectory(){
String resourceName = Thread.currentThread().getContextClassLoader().getResource("data").getFile().replace("%20", " ");
File file = new File(resourceName);
return file;
}
}
in my program I have the main method
public static void main(String args[]){
System.out.println(Data.getSpecialDirectory());
}
When I execute the getSpecialDirectory() in a junit test within the data program, the resource is fetched and all is well.
When I execute the getSpecialDirectory() in the main method outside the data program (imported jar) I get the jars data directory and not the directory the program executing the thread is expecting.
I figured getting the parent class loader would have solved this issue... I believe I may have a fundamental issue in my understanding here.
For clarity:
(library)
Line 15 of this file: https://gist.github.com/AnthonyClink/11275442
(Usage)
Line 31 of this file:
https://gist.github.com/AnthonyClink/11275661
My poms may have something to do with it, so sharing them is probably important:\
(Library)
https://github.com/Clinkworks/Neptical/blob/master/pom.xml
(Usage)
https://github.com/Clinkworks/Neptical-Maven-Plugin/blob/master/pom.xml
Maven uses the target/classes and target/test-classes directories to compose the classpath used to run unit tests. The content of your src/main/resources and src/test/resources gets copied to these locations together with the compiled java sources (the .class files).
java.lang.ClassLoader.getResource returns a java.net.URL.
In the unit test situation, ClassLoader.getResource returns a file:// schemed URL, and your code works as expected.
When your code is executed when packaged in a jar file, ClassLoader.getResource no longer returns a file:// schemed URL. It can't because the resource is no longer a separate entity in a file system - it's buried inside the jar file. What you actually get is a jar:file:// schemed URL.
jar: URLs cannot be accessed through a [java.io.File] object.
If you only need to read the content of the resource you should use java.lang.ClassLoader.getResourceAsStream(...) and read the content from that.
Note that it is not possible to update the content of class loader resources.
Do you want the directory where the Java program was loaded from ? Can try
File f = new File(".").getCanconicalFile();
Or if you want all the places could try parsing the classpath from System.env or use the default class loader
If you want a directory relative to the jar from where your classes were loaded: Quoting from http://www.nakov.com/blog/2008/06/11/finding-the-directory-where-your-java-class-file-is-loaded-from/
URL classesRootDir = getClass().getProtectionDomain().getCodeSource().getLocation();
The above returns the base directory used when loading your .class
files. It does not contain the package. It contains the classpath
directory only. For example, in a console application the above
returns someting like this:
file:/C:/Documents%20and%20Settings/Administrator/workspace/TestPrj/bin/
In a Web application it returns someting like this:
file:/C:/Tomcat/webapps/MyApp/WEB-INF/classes/
FYI This might apply if the user id running program cannot read all folders: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getProtectionDomain%28%29
or pass a .class object of the calling class as a parameter and get its classloader
There is no guarantee that you have a directory for your resources as far as I know. Java provide methods to get a resource as a InputStream, but nothing that can easily get the File for a resource, although it is possible to get the URL for a given resource.
If you need a special working directory in your application, I recommend having that passed as a system property, a program parameter, a web application parameter, or something else that lets you know where your application files are. You can even populate this directory with a ZIP file that you include as a resource in your application, as the ZIP libraries in Java do accept input streams as parameters.
While user #tgkprog is right and his answer correct, I can hardly imagine that you really want what you seem to have asked for and what he correctly answered in (3). Please edit your question and explain
what the output should look like if resourceName would be printed to the console,
if you really want the JAR file's location (in my test case that would be something like file:/C:/Users/Alexander/.m2/repository/com/clinkworks/neptical/0.0.1-SNAPSHOT/data, which does not make sense because you do not want to read from or even write to the local Maven cache),
or if you maybe rather want to read a resource directly from the JAR file or any other location such as the current working directory etc.
Otherwise I am afraid there is no good way to answer the question.

Java: simple JAR project, when run, cannot find an imported class in a second simple JAR project even though second JAR passed via -classpath

I have written two simple Java classes (one of them containing "main()", and the other called by "main()").
Class #1 (containing "main()"):
package daniel347x.outerjar;
import daniel347x.innerjar.Funky;
public class App
{
public static void main( String[] args )
{
Funky.foo();
}
}
Class #2 (called by "main()"):
package daniel347x.innerjar;
public class Funky
{
public static void foo()
{
System.out.println( "Funky!" );
}
}
The above classes appear in different project root folders, and use Maven as the build system (each project has its own POM). The pom.xml file for the main project includes the proper entry to add daniel347x.outerjar.App as the main class, and it properly includes the dependency on daniel347x.innerjar. Both projects build successfully into JAR files.
I use NetBeans to wrap these as Maven projects (in fact, I used NetBeans to create both projects). When I run the main project from within NetBeans, it runs successfully and I see Funky! as the output.
However, when I attempt to run the main class straight from the Windows command line (cmd.exe), passing the JAR file containing Funky on the command line's classpath, as such:
java -classpath "P:\_Dan\work\JavaProjects\JarFuckup\innerjar\target\innerjar-1.0-SNAPSHOT.jar" -jar "P:\_Dan\work\JavaProjects\JarFuckup\outerjar\target\outerjar-1.0-SNAPSHOT.jar"
... I receive the dreaded NoClassDefFoundError:
Exception in thread "main" java.lang.NoClassDefFoundError: daniel347x/innerjar/Funky
at daniel347x.outerjar.App.main(App.java:7)
I have carefully confirmed that, inside the innerjar JAR file noted above containing Funky, that the path structure is daniel347x\innerjar and that inside the innerjar folder is the Funky.class file - and this file looks correct within a HEX editor where I can see the ASCII strings representing the name of the class.
The fact that the class can't be found defies my understanding of Java, which I thought allows you to pass JAR files as a -classpath parameter and it will be able to find classes inside those JAR files.
This very basic point has me flummoxed - an answer that explains what I am doing wrong would be greatly appreciated.
The classpath is ignored when using the -jar option. A way to run your app would be java -classpath "P:\_Dan\work\JavaProjects\JarFuckup\innerjar\target\innerjar-1.0-SNAPSHOT.jar";"P:\_Dan\work\JavaProjects\JarFuckup\outerjar\target\outerjar-1.0-SNAPSHOT.jar" daniel347x.outerjar.App
Perhaps a better approach would be to add a manifest file to the Jar that specifies the class path of the dependent Jars by relative paths. Then..
java -jar "P:\_Dan\...\outerjar-1.0-SNAPSHOT.jar"
..should do it.
Double clicking the main Jar will also launch it. That is mostly useful for GUIs.

How can I create a Class file and JAR file without main function?

How can I create the class file and jar file for this coding, when I compile this program its not working because there is no main function in the program. And also I am trying in command prompt but I don't know how to set the classpath? please help me
My Coding is here
public class NewLogFields implements ILogNotify
{
public void onLog(Level level, String comment, IMediaStream stream, String category,String event, int status, String context) {
if (category.equals(WMSLoggerIDs.CAT_session) && event.equals(WMSLoggerIDs.EVT_destroy))
{
Long csBytes = (Long)WMSLoggerFactory.getGlobalLogValue(WMSLogger IDs.FD_cs_bytes);
Long scBytes = (Long)WMSLoggerFactory.getGlobalLogValue(WMSLogger IDs.FD_sc_bytes);
System.out.println("disconnect: csBytes:"+csBytes+" scBytes:"+scBytes);
}
}
}
Once you compiled the coding in wowza media Serever the jar file is automatically created in the library folder,see your Installation Library folder.Still you have problem Gothrough this link Wowza Quick Guide
What do you want to do?
Create a class and an jar file out of this Java code so that you can use this in another Java program?
Then you have to compile it:
java NewLogFields.java
Looks like you are unable to compile it at all. This could be because the interface ILogNotify (or the jar that contains this) is not in the classpath.
You can include the path/jar containing this interface in the classpath by using:
javac -cp .;path_to_jar_or_class NewLogFields.java
where path_to_jar_or_class is the path to the folder or jar file that contains ILogNotify.
For example, this may be something like ./logNotify.jar or ./log/
You can set use switch -cp or -classpath with javac command.
for example javac -cp path and name of jat file or class file yourjavafile.java
create the class file using the compiler: javac NewLogFileds.java
create the jar file using the jar command: jar cvf stuff.jar NewLogFileds.class
You are correct that the program needs a main() function in order to run.
add:
public static void main(String args[]) {
// code here
}
With that you could run the code with or without the jar:
java NewLogFields
or
java -cp stuff.jar NewLogFields
There are ways of creating a MANIFEST file that tells java which class to run from the jar making the last line more simple.
The link that you provided tells you how to do it:
Compile your class in the normal way.
Create a JAR file containing your class in the normal way.
Copy the JAR file into the wonza installation's lib as described in the javadoc.
Edit the startup script to add the -Dcom.wowza.wms.logging.LogNotify=... option to JAVA_OPTS ... as described in the javadoc.
The "full-path-to-your-ILogNotify-class" is actually supposed to be the fully qualified class name of your class; it is obvious from the examples.
Edit WowzaMediaServerPro-Service.conf and log4j.properties as described in the javadoc.
Restart the server.
If you put your JAR file in the directory like the instructions tell you to, you won't need to modify the classpath by changing -cp argument.
Your class doesn't need a main method because it is not a free-standing application. Rather, it is a "plugin" class that gets dynamically loaded and instantiated by the Wowza core as required. The "-D..." option and the config file change tell the Wonza core which class to try to load.

Categories

Resources