I'm having trouble when one of the jars that my web app depends on tries to load a properties file from within the jar. Here is the code in the jar.
static
{
Properties props = new Properties();
try
{
props.load(ClassLoader.getSystemResourceAsStream("someProps.properties"));
} catch (IOException e)
{
e.printStackTrace();
}
someProperty = props.getProperty("someKey");
}
The properties file is in my "src/main/resources" directory of the Maven project. When I run this code from my junit test in Eclipse, it executes just fine. When the project is built with Maven into a jar, and included as a dependency in my web app, it fails to locate the properties file. I know that the properties file is at the base directory of the depended on jar, I don't know how to fix this.
The problem is that you are using getSystemResourceAsStream. Use simply getResourceAsStream. System resources load from the system classloader, which is almost certainly not the class loader that your jar is loaded into when run as a webapp.
It works in Eclipse because when launching an application, the system classloader is configured with your jar as part of its classpath. (E.g. java -jar my.jar will load my.jar in the system class loader.) This is not the case with web applications - application servers use complex class loading to isolate webapplications from each other and from the internals of the application server. For example, see the tomcat classloader how-to, and the diagram of the classloader hierarchy used.
EDIT: Normally, you would call getClass().getResourceAsStream() to retrieve a resource in the classpath, but as you are fetching the resource in a static initializer, you will need to explicitly name a class that is in the classloader you want to load from. The simplest approach is to use the class containing the static initializer,
e.g.
[public] class MyClass {
static
{
...
props.load(MyClass.class.getResourceAsStream("/someProps.properties"));
}
}
For the record, this is documented in How do I add resources to my JAR? (illustrated for unit tests but the same applies for a "regular" resource):
To add resources to the classpath for
your unit tests, you follow the same
pattern as you do for adding resources
to the JAR except the directory you
place resources in is
${basedir}/src/test/resources. At
this point you would have a project
directory structure that would look
like the following:
my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- META-INF
| |-- application.properties
`-- test
|-- java
| `-- com
| `-- mycompany
| `-- app
| `-- AppTest.java
`-- resources
`-- test.properties
In a unit test you could use a simple
snippet of code like the following to
access the resource required for
testing:
...
// Retrieve resource
InputStream is = getClass().getResourceAsStream("/test.properties" );
// Do something with the resource
...
Related
I have a spring boot project in which there are multiple modules, I want to have each module separate application properties file, but when I added properties file in all modules, it's still picking properties from main application properties file.
Project Structure:
|-- Dockerfile
|-- build.gradle
|-- modules
| |-- application
| | |-- build.gradle
| | `-- src
| | `-- main
| | |-- java
| | | `-- org
| | | `-- example
| | | |-- CoreApplication.java
| | `-- resources
| | |-- application-beta.properties
| | |-- application-dev.properties
| | |-- application-local.properties
| | |-- application-prod.properties
| | |-- application-test.properties
| | `-- application.properties
| |-- config-management
| | |-- build.gradle
| | `-- src
| | `-- main
| | |-- java
| | | `-- org
| | | `-- example
| | | `-- controller
| | | `-- TestController.java
| | `-- resources
| | |-- application-beta.properties
| | |-- application-dev.properties
| | |-- application-local.properties
| | |-- application-prod.properties
| | |-- application-test.properties
| | `-- application.properties
`-- settings.gradle
application.properties in config module
config.hello=hello-from-config
application.properties in application module
config.hello=hello-from-application
TestController.java in config module
#RestController
public class TestController {
#Value("${config.hello}")
private String hello;
#GetMapping("hello")
public String get() {
return hello;
}
}
After calling /hello api, response: hello-from-application
This isn't a complete answer to your question but more a list of advices I think you should follow when designing your multi-module application project.
With spring many things are easier to configure with #Configuration beans. On many occasions, you'll be forced to have such beans to configure specific functionalities. These configuration beans are also a great way of including a configuration of one module in another.
What I do is the following - each module has one main #Configuration bean. This bean #Imports all other #Configuration beans inside your module, as well as, loads the properties file and imports the main #Configuration beans of the modules and maybe external dependencies your module depends on.
You should remember that spring, and java in general uses the classloader to load these .properties files that you have in the resources folders. The way you have organized the .property files currently they override each other; depending on how spring boot works the classloader will either load the first *.properties file it encounters, or maybe, your extra property files won't even make it into the shaded jar file. As a solution, use packages. Each module should have all of its stuff in a specific package, this includes the configuration files.
Do not include environment-related configuration files in your application source code. Move it to your deployment procedures. You can have samples of these environment-related files in your /docs or /distribution folder in your project, but have them here as documentation and not as actual configurations used in these environments. In 99% of the cases, environment-related configurations should be stored separately from your compiled application, the way you have it now they are compiled into the application itself.
Hope this was helpful.
P.S.
Once you organize the config files in the manner I describe, you may still end up fighting a battle against Spring's property file loader(don't remember the exact name), but that's a separate topic, and there are already many questions on that topic here.
I have build my project with maven and spring framework using text editors.
I am able to run the project the root folder using the command on terminal
mvn spring-boot:run
I have referenced to my source files inside java file using the java statement
Document doc = builder.parse("src/main/resources/data/resorts.xml");
Everything works fine.
When I export the whole project as a war file using the command
mvn package
on terminal
I get a war file inside the target folder of the root directory
I run the war file using the command
java -jar filename.war
There is no compilation error but during runtime it shows the error java.io.FileNotFoundException
I think I have not specified the path of the reference file correctly
Can you mention how the relative path must be mentioned in the the path string to make it able to be run from the war file.
My directory structure is
.
|-- src
| `-- main
| |-- java
| | `-- hello
| | `-- org
| | `-- json
| `-- resources
| |-- data
| `-- templates
`-- target
|-- classes
| |-- data
| |-- hello
| |-- org
| | `-- json
| `-- templates
|-- generated-sources
| `-- annotations
|-- gs-handling-form-submission-0.1.0
| |-- META-INF
| `-- WEB-INF
| |-- classes
| | |-- data
| | |-- hello
| | |-- org
| | | `-- json
| | `-- templates
| `-- lib
|-- maven-archiver
`-- maven-status
`-- maven-compiler-plugin
`-- compile
`-- default-compile
33 directories
The java files are inside the hello directory.
You are probably experiencing problems with the path received from the URI class to a file located inside a jar.
Application.class.getClassLoader().getResource("path-to/filename.txt").getPath()
Outputs: /path-to-your/application.jar!/path-to/filename.txt
If you try to create a File object or a Stream to that path it will fail with FileNotFoundException
If possible you should change the class Document to receive the content of the file or a InputStream.
Then you can use the classloader to fetch the stream for the file instead of the path.
In your case:
InputStream is = Application.class.getClassLoader()
.getResourceAsStream("data/resorts.xml");
And then create the Document with the is object.
I swear to god. I'm new in Maven. So finally i'm confused in between this file called as appTest.java. I created a new project for Maven in Eclipse. But i see three files known as pom.xml, App.java, Apptest.java.
That file is in the folder of src/test/java.
What's the aim of test folder inside maven project? Can you please tell me?
Now i'm confused about Apptest.java.
It contains this source code:
package com.faltu.blah;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class AppTest
extends TestCase
{
public AppTest( String testName )
{
super( testName );
}
public static Test suite()
{
return new TestSuite( AppTest.class );
}
public void testApp()
{
assertTrue( true );
}
}
Please, Help!!
Help, would be appreciated!
Something like below directory is created
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java
The src/main/java directory contains the project source code, the
src/test/java directory contains the test source, and the pom.xml file
is the project's Project Object Model, or POM.
The test folder is where you put all your test cases, The files under test folder will not be the part of your final distribution.
When you run a mvn test command, maven will be using these test cases to make sure every thing is fine.
And every time you run a build, maven is going to first run your test cases to check if all your test cases are passed.
I am trying to load a resource that is contained within an embedded JAR file. The project is actually deployed in JBoss using an EAR file with the following structure:
deploy.ear
|
|-> project.sar
|
|-> sub_project.jar
| |
| |-> settings.xml
|
|-> com/path/project/
|
|-> main.class
From main.java I'd like to get a InputStream for settings.xml. What is the correct way to do this?
My current understanding that the following code should work, but it is returning null:
this.getClass().getResourceAsStream("settings.xml");
Update
After some trial and error, the following statements work:
getClass().getResourceAsStream("/settings.xml");
getClass().getResourceAsStream("/sub_project.jar/settings.xml");
getClass().getClassLoader().getResourceAsStream("/settings.xml");
getClass().getClassLoader().getResourceAsStream("settings.xml");
getClass().getClassLoader().getResourceAsStream("sub_project.jar/settings.xml");
getClass().getClassLoader().getResourceAsStream("/sub_project.jar/settings.xml");
This might be a good resource: http://one-jar.sourceforge.net/version-0.95/
The main idea is that the inner JAR is not loaded by the ClassLoader that loaded the outer JAR automatically, you need to do so manually, e.g. by using a StreamClassLoader to load the inner jar
Only then, from your own ClassLoader you can get that resource using getResourceAsStream(...)
I currently have the following directory structure for my code:
src
|-- main
| `-- java
| `-- com
| `-- upthescala
| `-- tags
| `-- ViewProtectTag.java
|-- test
|-- pom.xml
|-- .project
|-- .classpath
`-- .hgignore
I want to include a tld file for my JSP tag, and I'm not sure where to package it. My initial thought is to add a src/main/resources directory and put META-INF/viewprotect.tld in there.
My initial thought is to add a src/main/resources directory and put META-INF/viewprotect.tld in there
And that's a good initial thought.