I have build a jar file of classes and configuration files. The configuration.yml file is located in root of the jar. When I try to run the application using the following command:
java -jar target/drop-wizard-0.0.1-SNAPSHOT.jar server configuration.yml
I get the exception below. How can I specify file located in jar from command prompt?
Exception in thread "main" java.io.FileNotFoundException: File configuration.yml not found <br>
at io.dropwizard.configuration.FileConfigurationSourceProvider.open(FileConfigurationSourceProvider.java:14)<br>
at io.dropwizard.configuration.ConfigurationFactory.build(ConfigurationFactory.java:75)<br>
at io.dropwizard.cli.ConfiguredCommand.parseConfiguration(ConfiguredCommand.java:114)<br>
at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:63)<br>
at io.dropwizard.cli.Cli.run(Cli.java:70)<br>
at io.dropwizard.Application.run(Application.java:72)<br>
at com.flightnetwork.dropwizard.example.HelloWorldApplication.main(HelloWorldApplication.java:10)<br>
It is possible to load a yaml file from a class path since Dropwizard 0.9.1 version.
Just configure Application with ResourceConfigurationSourceProvider in the similar manner:
public class MicroUsersApplication extends Application<MicroUsersConfiguration> {
#Override
public void initialize(Bootstrap<MicroUsersConfiguration> bootstrap) {
bootstrap.setConfigurationSourceProvider(
new ResourceConfigurationSourceProvider());
}
}
And for configuration.yml in the root of a jar:
java -jar target/drop-wizard-0.0.1-SNAPSHOT.jar server configuration.yml
For configuration.yml in the /com/some/configuration.yml from the jar root
java -jar target/drop-wizard-0.0.1-SNAPSHOT.jar server com/some/configuration.yml
Please, note — there is not a leading / in the path com/some/configuration.yml. Looks like, this behaviour will be kept till 1.1.0 release: Fix #1640: ResourceConfigurationSourceProvider - process a path to the resource in the more sophisticated way.
If you use more recent Dropwizard version, you can implement your own ResourceConfigurationSourceProvider — it is pretty simple.
configuration.yml is expected to be in the working directory i.e. on the filesystem, because this is how you try to read it. If you want to read it from jar file or from classpath in general you need to use getResource or getResourceAstream methods. (please see this similar question and answer)
EIDT
If you want to read the config from a resource inside your jar then you might want to configure your application to use UrlConfigurationSourceProvider instead of FileConfigurationSourceProvider and pass it the URL which you can obtain from getResource, the open method of the underlying interface expects a String as parameter, so you will need to use URL#toString on the result of getResource.
Try executing the command with absolute paths instead, apparently configuration.yml isn't in the run folder.
Example when configuration.yml is in /tmp
java -jar target/drop-wizard-0.0.1-SNAPSHOT.jar server /tmp/configuration.yml
I don't think it's possible to feed dropwizard a yml file within jar. It needs to be on the file system AFAIK. UPDATE: it looks like it's possible but I'm leaving this as it's still a solution.
If you don't want to expose configuration details to outside, then you need to configure it using the Configuration class, by setting the default values in the constructor. It gets quite ugly though since it's so nested. I don't like how dropwizard enforces the yml dependency myself.
An example I was using for my tests:
public class TestConfiguration extends Configuration {
public TestConfiguration() {
super();
// The following is to make sure it runs with a random port. parallel tests clash otherwise
((HttpConnectorFactory) ((DefaultServerFactory) getServerFactory()).getApplicationConnectors().get(0)).setPort(0);
// this is for admin port
((HttpConnectorFactory) ((DefaultServerFactory) getServerFactory()).getAdminConnectors().get(0)).setPort(0); } }
Related
My Springboot Application is running fine in IDE but when I create fat jar file and run on docker it gives the error. I am connecting my application with firebase so i want to include the serviceAccountKey.json file from the resource folder. The application runs fine in my ide, but while deploying it over the docker container it gives the error of file not found. Though when include the file and print it path it doesn't give any sort of error . But when i give the file path to fileInputStream it produces the error. I have tried multiple ways but nothing seems to work. I'm including the file using classLoader.getResource("filename.json").
I tried to skip the inclusion of file and do it by saving files content in a string and then sending it to stream but this method crashes the server whenever i query firebase.
this is the code where error is occurring. Notice that I'm printing the file path and it gets printed in the output before showing error. I have also tried file.getAbsoluteFile instead of path but doesn't work. Probably I'm doing it wrong or probably i have to mention the path in some other place as well which i don't know about. If anyone has done this before then please help me on this.
File path is getting printed but FileStream can't get it
An alternative to having a credential in a json file that is packaged with the application, would be that you set an environment variable upon starting the application, and instead load the key via application.yml. This way, you don't need to package the secrets into the application jar file.
1. create config class
#Configuration
#ConfigurationProperties(value = "my-custom-config")
public class MyConfig {
private String serviceAccountKey;
// getters/setters etc. if not using lombok
}
2. use above config
in other spring beans by injecting the config class, and retrieve the secret with getter, e.g. config.getServiceAccountKey();
3. Add config to your application.yml file
# application.yml
my-custom-config:
serviceAccountKey: ${ENV_VARIABLE_NAME} # <---- this way you can bind an env variable to your config.
4. Define env variable in container on startup
On instantiating the docker container, provide env option and define an environment variable.
docker run -env ENV_VARIABLE_NAME=<value> ...
With this setup (from Eclipse using Windows10)
I was able to correctly start my SpringBoot application. This one worked too (same directory pattern):
Now I'm packaging my project as JAR and I want to use an external properties file. I had an teste32.yml file beside my JAR at the same directory (also tried to use it inside /config directory, as show here, but it didn't work either)
I want to dynamically use a properties file beside my JAR file everytime. Doesn't matter at which directory they are, I wanted to dynamically point to a properties file always at the same directory as the JAR is. I want to say to my client: "take this JAR and this file, put them wherever you want and run this command X and everything will be alright". I'm trying to discover command X but before I add some dynamic path, I'm trying with absolutes paths. I'm using this:
java -jar myJar.jar -Dspring.config.name=teste32 -Dspring.config.location=C:\workspace\myProject\target\
I manually copied teste32 inside target\ to test this. But this didn't work. This didn't work either (only spring.config.location variants):
-Dspring.config.location=file:C:\workspace\myProject\target\
-Dspring.config.location=classpath:/
-Dspring.config.location=file:C:/workspace/myProject/target/
I also tried with no spring.config.location, only name
So my questions are:
What does classpath: and file: mean? Until now I got the 2 correct setups by pure luck and I would like to understand when to use them.
When I have my project package as a JAR, what classpath becomes?
Finally, which combination is necessary to dynamically use a properties always at the same directory as the JAR?
UPDATE
Using --debug at the correct example got me this line at the very begging (Spring banner was still visible):
2018-09-25 15:45:14.480 DEBUG 11360 --- [ main] o.s.b.c.c.ConfigFileApplicationListener : Loaded config file 'file:src/main/resources/xirulei/teste32.yml' (file:src/main/resources/xirulei/teste32.yml)
But after moving myJar.jar and teste32.yml to a specific directory and running java -jar myJar.jar -Dspring.config.name=teste32 --debug (without spring.config.location, since teste32 is at the same directory as JAR), I simply didn't get any ConfigFileApplicationListener debug line.
a) java -jar myJar.jar -Dspring.config.name=teste32 -Dspring.config.location=C:\workspace\myProject\target
Did you check content of target dir? I'm pretty sure your cfg file is placed to target\classes\xirulei and it is why Spring cannot find it in target
b) When you place teste32.yml in the same directory as jar file then Spring must be able to find it (given this directory is working directory) without -Dspring.config.location (but you still need to provide -Dspring.config.name=teste32)
c) When you use -jar and do not provide additional class paths then classpath: points to the root of packages inside jar. Spring cannot find your file at classpath:/ because your file is at classpath:/xirulei/
Well, after all it was a simple mistake. As documentation says and as already pointed here, it should be
java -jar myproject.jar --spring.config.name=myproject
and not
java - jar myproject.jar -Dspring.config.name=myproject
As stated on question, only when using Eclipse -D(JVM argument) is necessary. When using bash/cmd, just --(program argument) is the correct option:
I try to deploy a program as windows service with apache commons daemon. i have everything set up fine beside the classpath.
Classpath=C:\test\test-service\lib\*
specifies where the service itself lies, but the service needs some configuration files to run and these are under
Classpath=C:\test\test-service\conf\*
now i struggle to get it to work so that the program uses C:\test\test-service\* as classpath and not just one of the both specified above. sadly C:\test\test-service\* does not work and throws a ClassDefNotFoundException for the starter class. that error is solved by C:\test\test-service\lib\* but then i get the error that my config files can't be read. therefore i thought, why not also add the config path to the classpath like this:
Classpath=C:\test\test-service\lib\*;C:\test\test-service\conf\*
but this still throws the FileNotFoundException. does anyone has a solution to this?
So I was able to solve this by myself. Following works:
Classpath= C:\test\test-service\conf\;C:\test\test-service\lib\*
it takes all files in conf folder by default as well as all files from lib as the * states
I uploaded a Spring application to Heroku but the application crashed with the following error:
java.io.FileNotFoundException: class path resource [com/myname/myapp/config/dao-context.xml
The file is definitely there, and it is in GIT, and the app runs successfully locally.
Any ideas what is happening here?
I suspect that when you are running locally, it is picking up the file on the classpath as a regular file on the filesystem (i.e. not inside of a JAR).
On Heroku, it is probably inside of a JAR file, which means it is not a regular file, and must be read as an input stream, which might look like this:
ClassLoader cl = this.getClass().getClassLoader();
InputStream inputStream = cl.getResourceAsStream("com/myname/myapp/config/dao-context.xml");
You can probably reproduce the problem locally by running the same command that's in your Procfile.
If this is not the case, then make sure the file exists on Heroku by running this command:
$ heroku run ls com/myname/myapp/config/dao-context.xml
For future visitors to this question, I overcame the problem by converting my DAO XML config file to the Java Config method, therefore Spring no longer required that XML file. This didn't directly solve the issue of being unable to find the XML file, but the added benefit is that I am now using the more modern and less verbose Java Config method.
Iam using spring boot org.springframework.boot.loader.JarLauncher to run my self executable spring boot app jar.
Now, I have my self executable jar packed like this (For brevity Iam just adding the files only that are needed to show the problem):
Main.jar
---META-INF
---lib
---a.jar
---com
---comp
---Abc.class
---folder1
---1.txt
---2.txt
---b.jar
and so on.
In my Abc.class Iam trying to load the resource 1.txt which is working fine when I run it in eclipse; but the story starts when I run using command line as self executable jar. I was not able to read that resource and ends up with null pointer error.
After reading few threads, I learnt that my IDEs does some magic on Class Loaders and so it was working fine, which will not be the case when I run it as executable jar
This is how I was Loading the files and the all the possible options I have tried to no luck.
Option 1:
Abc.class.getResourceAsStream("\folder1\1.txt")
Option 2:
Abc.class.getClassLoader().getResourceAsStream("folder1\1.txt")
Option 3: Reading thread, I have tried considered the current thread class loader context as below too, But to no luck again
Thread.currentThread().getContextClassLoader().getResourceAsStream("folder1\1.txt")
Can any one advise. How should I write my code to be able to read my resource that is in the jar and by the class that is in the same jar ?
PS: Spring boot is not adding class-path entry to MANIFEST.MF and if I have to do something around that, how do I do that ? In-fact I tried -cp when running my jar setting it to current directory, but that have not worked either
In Spring, the best way to access a Resource is via Resource APIs. For a Classpath resource what you should use a ClassPathResource and it would look something like this:
Resource resource = new ClassPathResource("/my/resource.json", this.getClass());
After obtaining a Resource you can either get a File reference via getFile() or get an InputStream straight off by calling getInputStream().
Spring provides quite a few different implementations of the Resource interface, take a look at the list of known implementations in the docs
Use Spring's class ClassPathResource to load file from classpath.
For example you can read file into String like this from classpath:
String fileContent = FileUtils.readFileToString(
new ClassPathResource("folder1" + File.separator + "1.txt").getFile());
It doesn't matter what kind of build tool or project structure you are using as long as that file is on classpath.