JavaFX Spring ClassNotFoundException: org.springframework.context.annotation.AnnotationConfigApplicationContext - java

I want to build a runnable jar for a JavaFX application which uses depency injection (Spring framework libraries) to manage multiple FXMl files and multiple FXMLDocumentControllers.
However, when exeuting the jar a "ClassNotFoundException: org.springframework.context.annotation.AnnotationConfigApplicationContext" is reported.
Yet, I have added Spring library (3.2.7) to the project in Netbeans and it functions well within the IDE.
How can I assure, that the above class is available in the jar as well?

When compiling and packaging your code, the resulting jar usually only contains YOUR code. You need to add the dependent jar files to the classpath. What that means is, whenever you invoke java -jar yourapp.jar some.package.MainClass to run your application, you need to list all required jar files in the -cp option of the java command.
Another (bad) solution could be to use maven's assembly plugin (or some other means) to create a fat-jar, which essentially is a merge of yourapp.jar and all dependent jars.
Read: Building a fat jar using maven

Related

How can I make my Apache Derby database work when I run my generated jar file?

I have created a JavaFX application and have a generated Jar file (generated with Gradle) that will launch.
When the application does launch, it doesn't connect to the embedded database though. I feel as though I am missing something very simple but after a lot of research, I haven't been able to figure it out. When running the jar file from the command prompt, I get the following error:
java.lang.ClassNotFoundException: org.apache.derby.jdbc.EmbeddedDriver
From the reading I have done, I understand I may be able to add this to my classpath but I have not been successful with this after multiple attempts and I have made this application to be run on another computer. This is possible, right?
If possilbe, I would love to change something in my build.gradle file or surround the .jar in a folder or something like that that would make this simple for the person running the program. Program size is not a concern short of multiple gigabytes.
You've got two problems
The driver class is not in your app jar
If you embed that db into the app jar, you're not going to be able to write to it
You can make a 'fat jar' but the isn't going to solved the second problem. You really need to make an installer to do this, in order to leave the db in the file system, so it can be written to.
Problem
Part of what Gradle does is dependency management. That means it knows what dependencies you need and how to find them (based on configurations in the build script). When you execute/build your application via Gradle the tool will automatically search repositories, download+cache dependencies, and place those dependencies on the class-path/module-path. Once you deploy your JAR file Gradle is no longer involved, so your deployment is responsible for including the needed dependencies.
In other words, you need to ship your application's dependencies with your application JAR file.
Solutions
You basically just need to make sure you include your application's dependencies with your application. Here are at least three ways to do that.
Copy Dependencies
Copy the dependencies into a build folder as part of the build process. Here's an example of such a task, using the Kotlin DSL:
tasks {
val jar by existing(Jar::class)
val copyDependencies by registering(Copy::class) {
from(configurations.runtimeClasspath)
into(jar.get().destinationDirectory)
}
jar.configure {
finalizedBy(copyDependencies)
}
}
Now if you execute ./gradlew jar Gradle will create the JAR file and then copy the dependencies into the same directory as the JAR file. Then you just need to make sure all the JAR files are deployed together.
If I remember correctly, the default class-path is the working directory. But to specify the class-path you would use -cp, -classpath, or --class-path when executing your application. The module-path, if needed, is set with -p or --module-path.
Fat JAR
Create a so-called "fat" or "uber" JAR file. That's a JAR file that includes not just your own application code but all your application's dependencies as well. You could configure the jar task for this, but it would probably be easier for you to simply apply the Gradle Shadow Plugin.
// Kotlin DSL
plugins {
id("com.github.johnrengelman.shadow") version "<version>"
// other plugins...
}
And then you'd create the fat JAR with ./gradlew shadowJar. See the user guide for more information.
Self-Contained Application
Create a self-contained executable using a tool like jpackage. This tool gives you an application that has all its code and the JRE embedded, and then gives you an installer or native executable (e.g. exe on Windows). Here's the user guide for jpackage. There are Gradle plugins to make using jpackage from Gradle easier, such as The Badass JLink Plugin.
Note jpackage was added in Java 14 and was incubating until Java 16. Also note that jpackage can't "cross-package". That is to say, if you build your application on Windows then you can only create installers/executables for Windows; same for MacOS and Linux. If you need to package for multiple platforms then you'll need access to each platform.
JavaFX
Since you've tagged this question with JavaFX I want to give a note of caution. Though if you're not using JavaFX 9+ then this is not relevant to you.
Technically JavaFX only supports being loaded as named modules. That means it needs to be placed on the module-path, either via --module-path or by including it in the custom-runtime image built by jlink / jpackage. As of JavaFX 16 a warning is now emitted if JavaFX is loaded from unnamed modules (i.e. the class-path).
Executable JAR files are placed on the class-path. That includes fat JARs. And if you are not using a JDK that includes JavaFX—meaning you have Gradle pull in the JavaFX dependencies—then JavaFX will be included in your fat JAR and be placed on the class-path. Now, despite not being supported and now emitting a warning, nothing seems to currently break if JavaFX is on the class-path. Except for one caveat: Your main class must not be a subclass of javafx.application.Application. You'd have to create a separate main class that simply launches JavaFX.
Because of all this, I would highly recommend using jpackage to deploy JavaFX applications. You may want to read this Q&A as well.

Building a fat JAR for Spring application without Maven or Gradle

I built a Spring application using Eclipse. Due to various reasons, I was not able to set the project up as a Maven or Gradle project, but rather with the external JAR files explicitly downloaded and added.
Currently I can run the application, Spring starts up normally and behaves fully as expected. The problem occurs however as soon as I want to package the project.
As there is no other option, I have to use Eclipse's packaging tools. This is what I do:
Export -> Java -> Runnable JAR file
Then I check the option Extract required libraries into generated JAR.
When executed the resulting JAR file always throws this error:
ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalArgumentException: No auto configuration classes found in META-INF/spring.factories.
If you are using a custom packaging, make sure that file is correct.
This spring.factories file looks like this:
org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
I am aware of the solutions to this problem involving the use of Maven or Gradle. But these can not be applied here.
How could I get the fat JAR to run without Maven or Gradle?

Gradle: Create a non-executable jar and executable shell script with dependent libraries as a package distribution

I am not a big fan of creating fat executable jars for java programs as it involves a massive overhead when I have multiple executable programs from the same project.
I want to be able to create a single library-like jar and create corresponding .sh scripts which pretty much have the structure of:
java -cp classpath_libs main_class program_args...
or any other executable where I can customize it to my needs but in a similar fashion(ex: hadoop jar project_jar main_class classpath_libs program_args). Is this achievable in gradle? if so, how? Note, I need to create multiple scripts using different main classes from a single project.
Key requirement here is to be able to use final fully resolved classpath string.
UPDATE: I have seen examples of using the application plugin but it creates an executable jar with dependent libraries packaged into it. This is NOT what I am looking for.
So far as I have found, it appears there's no plugin that handles this directly. So, I used the java-library plugin, used the configurations.runtime classpath value and created the necessary scripts and the copy task to copy the libraries necessary into the necessary directories. For anyone interested, you may also try the distZip option in application plugin where gradle does create scripts for execution and package the necessary libraries in a distribution. You can take a look at the output of the script to see how the classpath is structured and create something similar.

How Can I Get Jars Inside Another Jar on the Classpath?

I have a Spring Boot application that loads zero or more external jars from a known location during startup. Application is started using PropertiesLauncher by executing java -Dloader.path=application.jar,BOOT-INF/lib,jars/ -jar application.jar -XX:PermSize=512m -XX:MaxPermSize=512m. The external jars are built in maven using the MODULE configuration.
These jars primarily contain Spring managed classes such as services and controllers. When this is the case, everything loads as expected. However, if i attempt to load a jar that needs access to the jars in its own internal /lib folder, startup fails with ClassNotFoundException. If i use the fat jar model of bundling these dependencies in application.jar, but i'd prefer not to bloat that jar with library files that may never be used if at all possible. Is it possible to get jars within a jar built as a MODULE onto the classpath where PropertiesLauncher can find them?

What is the difference between setting the classpath and java build path in eclipse?

What are the different ways that java programs gain access to external libraries. There is setting a classpath, modifying the build or build path, but I've seen other ways of adding jars.
Why do some libraries have to be added to the classpath while others do not. For example I'm using JSF, WTP tools, and other extra libraries but they are not in my buildpath when I view the build path of my project.
The classpath is used to find classes when executing a Java program. The build path is used when Eclipse is compiling a Java program.
The Java Build Path is just an Eclipse thing. It's where Eclipse finds the classes needed to compile and run the classes of the project. It's thus both th compile and the run classpath.
In the case of a webapp, the webapp runs inside a Java EE web container. The web container gives access to standard Java EE classes (javax.servlet, etc.). Moreover, all the jars in WEB-INF/classes are automatically included in the classpath of the web app. So Eclipse doesn't need you to specify them in the Java Build Path. They're included automatically.
On development time.
A build path is one where you can explicitly point to third party software / jars.
By default not all third party software are added into your classpath, hence you may have to explicitly add that to your path.
On runtime.
On the other hand when you run your applications from the command line, you would prefix the classpath by using -cp to specify the third party jars.
For example in web projects you would add it to your web-inf library when you deploy.
A classpath is simply an array of classpath entries (IClasspathEntry) that describe the types that are available. The classpath is an environment variable that tells where to look for class files and it is generally set to a directory or a JAR (java archive) file.
The Java build path is reflected in the structure of a Java project element. You can query a project for its package fragment roots (IPackageFragmentRoot). The build path is the classpath that is used for building a Java project (IJavaProject).

Categories