I have the programming game 'Robocode' in my project root so I can run the project anywhere and not have it installed in C:/robocode. I have a run configuration with the following options;
Main Class: robocode.Robocode
VM Options: -Xmx512M -Dsun.io.useCanonCaches=false -Ddebug=true -DNOSECURITY=true -cp libs/robocode.jar
Working directory: MY_ROOT\robocode_master
JRE: Default(9.0.1 - SDK of my main module)
I'm writing some custom functionality for an AdvancedRobot that connects to a MongoDBAtlas Cluster for necessary data. I'm using mongo-java-driver-3.6.1. The .jar has been added as a library to IntelliJ, then as a compile dependency on the main module. It works fine in testing, I can download documents etc.
To illustrate, the libraries are shown here in the Project structure pane.
I have set the compile output path to the robocode_master/robots directory so that when I run Robocode from IntelliJ, it will see the custom robot .class files in the correct directory and allow me to add them to a battle.
The problem is when I start the battle and the robot tries to do what it needs to do, it throws a java.io.FileNotFoundException and is trying to find the necessary library files from the robocode_master/robots directory.
For example, the first thing it does is connect to the DB;
java.io.FileNotFoundException: MY_ROOT\robocode_master\robots\com\mongodb\MongoClient.class (The system cannot find the path specified)
When I have my project output paths set to the robots folder, upon launching Robocode, it throws a bunch of FileNotFoundExceptions. But if I switch the options to 'Inherit project compile output path', then launch Robocode, I don't get the exceptions upon launch. But now of course, my robots aren't in the default directory, so it can't see them. So I add the new path in out/production/... to Robocode in the GUI and reboot, and I then get the same exceptions from the robots. It now tries to look for the files in out/production/.../com/mongodb/MongoClient.class
How can I 'tell' Robocode to look for the libraries in their default location on the classpath?
Robocode will look for robot classes in your /robots folder. If your robot is located somewhere else, you need to tell Robocode where to locate these from the Robocode UI by setting with the Developments Options. Robocode has it's own class loader for loading Robot classes - but only robot classes.
Other classes/libraries must be specified on the ordinary classpath for Robocode using the -cp or -classpath for the java command (VM Options) like done for any other Java application.
Also notice, that you should use the VM Options that comes with Robocode - like the ones specified in the robocode.bat file. Especially when you use Java 9 or newer:
java -Xmx512M -cp libs/robocode.jar -XX:+IgnoreUnrecognizedVMOptions "--add-opens=java.base/sun.net.www.protocol.jar=ALL-UNNAMED" "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED" "--add-opens=java.desktop/sun.awt=ALL-UNNAMED" robocode.Robocode %*
You could copy this into "run_my_stuff.bat" and add stuff to the -cp right after libs/robocode.jar.
However, I am not sure if it will work with the Mongo driver. Robocode was built for simple robots with limited access to resources like CPU cycles, file access etc.
Related
I've been wanting to reverse engineer this clients launcher in an effort to understand how the game was launching as a Java application despite it only having a PE32 executable alongside it.
The launching of the client goes as follows:
java -Xmx384M -Dfile.encoding="UTF-8" -cp TargetBinary.exe com.java.client.Client
Now I was curious what TargetBinary.exe actually was, as this was being ran on a *NIX system. Running file I observed this output.
TargetBinary.exe: PE32 executable (GUI) Intel 80386 (stripped to external PDB), for MS Windows
The second part is the com.java.client.Client after the TargetBinary.exe, this stands out as a Java pathing which Client is my target.
Here are my questions:
How can Java add the TargetBinary.exe to its classpath?
As a followup, are there any recommendations to decompile it to the point where I can observe Client and more so understand how it was all packed together?
Being a Portable Executable (PE) the libs, code, etc should all be there inside the TargetBinary.exe and somehow Java knows what to do with it?
Zip files are read from the back, so it's easy to put a zip (jar) file at the end of an executable file, and have it work as both.
See https://en.wikipedia.org/wiki/ZIP_(file_format)#Structure
Try running jar -tvf TargetBinary.exe to see the names of the classes and resources in the jar. If you make the file a dependency of a project in your IDE you can see decompiled code and navigate around the project, and run it and set breakpoints.
I'm new to Java11/all the overcomplicated module stuff.
The Problem
So I exported my Java11/JavaFX11 program from Eclipse as a Runnable JAR. If I click the JAR, it runs perfectly fine (Eclipse includes all of the module settings and JavaFX itself automatically in the runnable JAR). However, if I try to bundle the JAR with a JRE and run it via the command line with the following BAT file:
#ECHO OFF
%~dp0\jre\bin\java -jar javaprogram.jar
pause
I get:
Error: JavaFX runtime components are missing, and are required to run this application
Press any key to continue . . .
How can I get it to just run the JAR file like it does when I click it?
Ways I've tried to fix it
The weirdest part is, if I just use:
java -jar javaprogram.jar
Which just accesses the installed JRE, it works again. It's only when I'm directly pointing it to a JRE at a specific path that it appears to break.
Alternatively, I'd just bundle JavaFX beside the JRE, but there doesn't seem to be a way to call --module-path with a relative path (googling this nets me a bunch of entirely unrelated stuff). It seems to demand an exact path, which isn't going to work if people are downloading a zip archive and extracting it. This would be redundant though because Eclipse is already packaging JavaFX with the JAR. I don't know why it's getting confused just because I'm calling it from the command line.
The project's code
The project I'm trying to get this to work with happens to be open source, so you can check out the code for it here:
https://github.com/SkyAphid/JDialogue
The main class is JDialogueCore.
Closing
I don't want to use installers since I think that's too bloaty. I'd like to be able to deploy my software like I always have by just putting them in an archive you can extract and run.
It's difficult to simply Google the problems as well since I keep getting completely unrelated results due to the broadness of the topic. Any direction/documentation relating to this problem would be greatly appreciated.
Thank you for your time!
While Java 8, 9, and 10 allowed a JavaFX Application subclass to act as a main class for program startup, that is no longer the case as of Java 11. Placing your public static void main method in a different class and making that class the main class solves the problem. (Source: https://github.com/javafxports/openjdk-jfx/issues/236)
Your command line invocation needs to specify both the location of the JavaFX jar files, and the location of JavaFX native libraries. Normally these are the same location in the JavaFX SDK, but they must be specified in different ways: the jar files go in the classpath or module path, while the native libraries’ location must be specified in a system property:
cd /d %~dp0
jre\bin\java -cp javaprogram.jar;javafx-sdk-11\lib -Djava.library.path=javafx-sdk-11\lib com.example.MyNonApplicationClass
If you define a module-info.java in your program, your .jar is a modular .jar, and you can benefit from the additional security of modules:
cd /d %~dp0
jre\bin\java --module-path javaprogram.jar;javafx-sdk-11\lib -Djava.library.path=javafx-sdk-11\lib -m com.example.myapp/com.example.MyNonApplicationClass
If your modular .jar file has a main class defined, you can omit the class name:
cd /d %~dp0
jre\bin\java --module-path javaprogram.jar;javafx-sdk-11\lib -Djava.library.path=javafx-sdk-11\lib -m com.example.myapp
Notice that relative paths work just fine with --module-path. Relative paths use the current directory as a base. The current directory is not changed merely by putting %~dp0 in front of the invocation of Java. The current directory is a property of the command line or script actively running, and can only be changed with commands like cd or pushd.
I currently wrote a simple GUI in Eclipse which runs as intended. I was hoping to export it so I can share it with my friend (who doesn't need to install eclipse and the java libraries). I tried all 3 library handling method Eclipse provides and none of them works. I read a little online and saw something about a manifest file, but wasn't quite sure what to do with it. Is it going to help?
This is where I placed the folder that comes with the .dll file.
This is the result. Am I doing something wrong?
As indicated by the error messages in the first screenshot, what you are missing here is the native library - the software library written and compiled to native code specific to the operating system. What you will need to do is provide the libraries specific to the operating system on which your software will run, eg. dlls for 32 or 64 bit Windows. The manifest does not provide the capability to include those libraries.
When the program is run on Windows, Java will look for native libraries in the following locations:
The current directory
The directories in the PATH environment variable
The directories in java.library.path (if it's specified)
It may be easiest to simply put all files in the one directory. If you do this, you should be able to run the program in the same way as you do now.
The java.library.path option is only needed if you want to put your native library files in a directory separate to the one in which you run your program and not on your PATH. It is only in this case that you will need to add java.library.path, eg. by adding -Djava.library.path=c:\path\to\your\lib after java. Also note that you may use a relative path, ie. a path that is relative to the directory you are in when you execute the command.
I also see from your later error messages that you have another dependency, but on a java library LeapJava.jar. As running a jar with -jar will only work if you have a single jar, but because you have more than one (your own program plus the dependency), you'll instead need to use the -classpath (or -cp for short) argument and add your main class. The classpath argument is a semicolon-separated list of classpath locations, while the main class is the one containing your public static void main method, eg. your.package.name.YourMainClass. So assuming your UI.jar is still in C:\Users\Ian\Desktop\Leap Data UI, you should be able to navigate to that directory and execute with:
java -cp UI.jar;UI_lib\LeapJava.jar -Djava.library.path="UI_lib\x64" your.package.name.YourMainClass
I tried to run FindBugs in command line and had troubles when specifying the project to be analyzed. I understand FindBugs works on bytecode (.jar, .class), so I wrote a HelloWorld program and made sure that it had some messy code that would be detected by FindBugs.
Then I tried:
java -jar D:/findbugs-2.0.3/lib/findbugs.jar -project HelloWorld/bin
which threw an exception:
java.lang.IllegalArgumentException: Can't read project from HelloWorld/bin
at edu.umd.cs.findbugs.Project.readProject(Project.java:774)
I also tried .class and .jar files, but nothing showed up:
java -jar D:/findbugs-2.0.3/lib/findbugs.jar -project HelloWorld/bin/Main.class
java -jar D:/findbugs-2.0.3/lib/findbugs.jar -project HelloWorld.jar
I checked the FindBugs manual about the command line option "-project", it says
The project file you specify should be one that was created using the GUI interface. It will typically end in the extension .fb or .fbp
I don't understand this. Does it mean that some pre-processing is required and FindBugs cannot check arbitrary .jar or .class or project directly? How can I get this .fb or .fbp extension?
Thanks.
The procedure is described on the FindBugs website:
Make sure you download the FindBugs distribution which includes the GUI (called Swing interface).
Extract your downloaded ZIP and add its bin folder to your PATH.
Type findbugs to open the GUI, then click New Project
In the dialog:
Enter a project name, say HelloWorld.
Where it says Classpath for analysis, give it the Jar with your .class files or a directory where the .class files are (such as build/classes/main or whatever; the package structure must start in this directory).
Where it says Auxiliary classpath, list any libraries required to load your classes.
Source directories works just like Classpath for analysis, but for .java files. FindBugs uses this to show you where in the code your issues are.
You can select (cloud disabled) as bug store.
Click Analyze.
Now you can save the project configuration as a .fbp project file.
Next time, you can start the analysis by running
java -jar D:/findbugs-2.0.3/lib/findbugs.jar -project HelloWorld.fbp
If you don't want to or cannot use the GUI, you can get the text-only version by adding the -textui option as first option after findbugs.jar. Output formats and behavior are configured via additional command line options.
However, most people use FindBugs integrated with their IDEs, or as part of a build process. Neither use case should require the GUI or command line versions. Take a look at the plugins for your IDE, it may save you a lot of time and they are really easy to use.
I'm currently working on a game based on Slick2D, but I ran into a problem.
When I try to run my game (no matter whether from dist or ide), I get the following error:
java.lang.UnsatisfiedLinkError: no jinput-linux64 in java.library.path
My directory structure is as following:
./lib contains all the .jar's for libraries
./natives contains the .dll's, .so's and .jnilib's
If I go to project options, and add -Djava.library.path=./natives to VM options, it works properly. But in that case, I'd need to have all the native libraries inside the root folder of the dist. So I want to have a separate folder for all the natives, so my first line in my main has this:
System.setProperty("org.lwjgl.librarypath", System.getProperty("user.dir") + "/natives");
But for some reason, this doesn't give a standard linking error (e.g. lwjgl not found) but for some reason picks jinput-linux64, but jinput is added as a library and is in the natives folder.
Is there anything I've done wrong or is there a better approach to distributing my game effectively overall?
Thank you !
What is wrong with placing the native libraries in your distribution? You cannot rely on your audience to have the libraries your application needs. Here is how I distribute stuff I make with slick:
MyFancyGame (Top directory)
-- libraries (mine and slick and lwjgl jars here)
-- lwjgl
-- native (dlls and so files go in here)
In the top directory I include a shell script & a batch file which contains one line:
java -ea -Djava.library.path="libraries/lwjgl/native/" -cp "libraries/*" com.MyGame.Main
This works on every computer I deploy to so long as they have java installed.