Configuring PropertySourcesPlaceholderConfigurer for WAR - java

I am trying to create a WAR that can use a spring properties file, but I seem to be having some issues with it.
I can see that my properties file in the base directory structure in target, and in a WAR when I make an exploded war. When I try to make a normal WAR, though, and deploy it, I a resource not found exception, specifically:
org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [service.properties] cannot be opened because it does not exist
From Jetty I have no such issue.
Here's my spring java configuration of the resource:
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
PropertySourcesPlaceholderConfigurer props = new PropertySourcesPlaceholderConfigurer();
props.setLocations(new Resource[] { new ClassPathResource("service.properties") });
return props;
}
And here's the relevant part of my POM. I added in the WAR configuration because that's what maven seemed to say to do here, but it didn't seem to help.
<build>
<resources>
<resource>
<directory>src/main/config/local</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<goals>
<goal>war</goal>
</goals>
<configuration>
<webResources>
<resource>
<!-- this is relative to the pom.xml directory -->
<directory>src/main/config/local</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
Anyone know what I'm doing wrong? Thanks!

Are you sure that your properties file is inside WEB-INF folder? If it outside and is just included in the root of the war file then it won't be found in the classpath. See maven-war-plugin documentation - to override default location (root of the war file) you need to add
<targetPath>WEB-INF</targetPath>

Related

How to access maven.build.timestamp for resource filtering in Quarkus

Accessing the version and name of the application works fine. But I also want to access the build date/time of a Quarkus application using maven. I know, there is a post for this already but I don't get it to work for Quarkus.
I have an application.properties file with:
# info properties
quarkus.application.version=1.0
quarkus.application.timestamp=${maven.build.timestamp}
In pom.xml, resource filtering is activated:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${version.resources-plugin}</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/classes/META-INF/resources/</outputDirectory>
<resources>
<resource>
<directory>name-frontend/dist/name-frontend</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
And in Java, accessing it via:
#ConfigProperty(name = "quarkus.application.version") // <--- works
String version;
#ConfigProperty(name = "quarkus.application.name") // <--- works
String name;
#ConfigProperty(name = "quarkus.application.timestamp") // <--- what to use here?
String buildDate;
Error:
Caused by: java.lang.RuntimeException: Failed to start quarkus
Caused by: java.util.NoSuchElementException: SRCFG00011: Could not expand value maven.build.timestamp in property quarkus.application.timestamp
Leaving the application.properties file without ${maven.build.timestamp} does let the build proceed, but there is simply no build time of course.
You likely want to use the Maven's Resource Filtering.
You would remove the maven-resources-plugin you have added, and simply configure Maven with:
<project>
...
<build>
...
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
...
</resources>
...
</build>
...
</project>
Then quarkus.application.timestamp=${maven.build.timestamp} in application.properties will be replaced automatically when you perform a build.

Serving static files from a jar file

I'm using grizzly StaticHttpHandler to serve the static files from an absolute path:
httpServer.getServerConfiguration().addHttpHandler(new StaticHttpHandler("/home/user/.../project/src/main/resources/static));
How can I package and serve the static files from the final fat jar generated by mvn assembly:single?
my part of my pom.xml file looks like
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
</build>
The given configuration
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>*</include>
</includes>
</resource>
</resources>
</build>
is not neccessary cause it's default.
Furthermore to get resources which are located there it's good to know that they will be packaged into the corresponding jar which can be accessed via
this.getClass().getResourceAsStream("/TheThingYoulikeToAccess.jpg"));
This defines a resource which is within the given jar file.
You can serve static files from a jar file using CLStaticHttpHandler like:
server.getServerConfiguration().addHttpHandler(
new CLStaticHttpHandler(new URLClassLoader(new URL[] {
new File("/home/myname/myjarfile.jar").toURI().toURL()}), // Path to the jar file
"my/jar/staticfiles-insider-jar/"), // the static files path inside the jar file
"/jarstatic"); // context-path

Exclude application.properties when generating war using spring boot and spring-boot-maven-plugin

I am developing a web application using Spring Boot, and want to generate war instead of jar.
It works very fine using the conversion from jar to war described here : http://spring.io/guides/gs/convert-jar-to-war/
But I want to exclude the application.properties from the war, because I use #PropertySource(value = "file:${OPENSHIFT_DATA_DIR}/application.properties") to get the file path on production environment.
This method works when generating my war, but in eclipse I can't run my application because application.properties not copied at all to target/classes :
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application.properties</exclude>
</excludes>
</resource>
</resources>
</build>
This method doesn't work at all, I think that spring-boot-maven-plugin doesn't support packagingExcludes :
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<packagingExcludes>WEB-INF/classes/application.properties</packagingExcludes>
</configuration>
</plugin>
</plugins>
</build>
Have you another suggestion?
Thanks
Try using the solution below. This will work:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
If you are using the above solution , while running the project in Eclipse IDE you may get error that the properties file is not found. To get rid of this you need to add the resources folder in Run as configuration.(Run configurations... -> Classpath -> User Entries -> Advanced... -> Add Folders)
When running in Eclipse, at your Run Configuration, you need to specify the path of the propeties to Spring Boot:
--spring.config.location=${workspace_loc:/YOURPROYECTNAME}/src/main/resources/
The solution I added is to unzip my packaged war, delete the file application.properties and create a new war named ROOT.war using maven-antrun-plugin and run some ant tasks.
this is what i added to my plugins in pom.xml :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>package</id>
<phase>package</phase>
<configuration>
<target>
<unzip src="target/${artifactId}-${version}.${packaging}" dest="target/ROOT/" />
<delete file="target/ROOT/WEB-INF/classes/application.properties"/>
<zip destfile="target/ROOT.war" basedir="target/ROOT" encoding="UTF-8"/>
<delete dir="target/ROOT"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
I named my target war as ROOT.war because I am using tomcat on openshift PaaS, so I just copy my ROOT.war and push to my openshift repo. That's it
What I understand from your question is, you want to use application.properties for your development. But you dont want to use it for production.
I would suggest using Spring profiles to achieve this.
In your properties file
Create a profile for development. Put all your development properties under it.
Do not create a profile for production in your properties file.
When you are developing, set active profile to development, so that the properties are loaded from your application.properties file.
When you run it in production, set active profile to Production. Though application.properties will be loaded into your WAR, since there is no profile for production, none of the properties will be loaded.
I have done something similar using YML. I am sure there must be a way to do the same thing using .properties file too.
spring:
profiles.active: development
--
spring:
profiles: development
something:
location: USA
unit1: Test1
unit2: Test2
You could change the profile in run time using
-Dspring.profiles.active=production
Try to using this solution:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.version}</version>
<configuration>
<addResources>false</addResources>
</configuration>
</plugin>
<addResources>false</addResources> will keep properties when you run mvn spring-boot:run

jar file gets corrupted while building with maven

while building a war file i am copying a set of jars from a location to a folder inside the war. While the files do get copied , however i think they get corrupted because the same class files of the jar when taken outside the war opens with a debugger while it does not open after taking from war file .
This is a part of my war pom.xml where i copy the jars
<execution>
<id>copy-jars</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/${project.artifactId}-${buildNumber}/somefolder</outputDirectory>
<resources>
<resource>
<directory>SomeSourceDirectory</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
SomeSourceDirectory has some jars and some other files
The result is:
myWar/somefolder/a.jar but when i open the classes inside this jar in a debugger..i get error in WinZip that
Invalid compressed data to extract.
Severe Error: Compressed data is invalid
However the same class file can be viewed when i view it in original folder i.e outside the war.
So is there a mistake while copying the jars?
Thanks.
Remove <filtering>true</filtering>, it corrupts the jar files.
Also, you can continue benefit to use maven filtering without corrupting jars inside.
We choose to exclude jar from filtered extensions.
In th pluginManagement section of the parent pom we put this configuration
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>jar</nonFilteredFileExtension>
<nonFilteredFileExtension>pdf</nonFilteredFileExtension>
<nonFilteredFileExtension>swf</nonFilteredFileExtension>
<nonFilteredFileExtension>zip</nonFilteredFileExtension>
<nonFilteredFileExtension>bz2</nonFilteredFileExtension>
<nonFilteredFileExtension>gz</nonFilteredFileExtension>
<nonFilteredFileExtension>acp</nonFilteredFileExtension>
<nonFilteredFileExtension>bin</nonFilteredFileExtension>
<nonFilteredFileExtension>odt</nonFilteredFileExtension>
<nonFilteredFileExtension>doc</nonFilteredFileExtension>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
Note we added jar extensions as well as default maven excluded filetypes (its a zip after all).
Besides avoiding corruption of the archive it also speeds up the process as it does not have to filter large files.
Try Maven Assembly Plugin. It's my favourite plugin to add custom resources to a *.war file. See also Pre-defined Descriptor Files.
I had a similar error when I've added
<copy ...>
<fileset ... />
<filterchain>
<tokenfilter>
<replacestring from="..." to="..." />
</tokenfilter>
</filterchain>
</copy>
to my copy task in ANT. It corrupted the jar files when copying them.
I've solved this by applying the filter ONLY on the targeted text files and not on jar files.
Just as addition to the other answers, the other option is to enable the filtering only for the resources that require filtering:
<build>
...
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<includes>
<include>core.properties</include>
</includes>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/resources</directory>
<includes>
<include>pdf/color_profile/sRGB.icc</include>
</includes>
</resource>
</resources>
</build>

If using maven, usually you put log4j.properties under java or resources?

Where should I put the log4j.properties file when using the conventional Maven directories?
src/main/resources is the "standard placement" for this.
Update: The above answers the question, but its not the best solution. Check out the other answers and the comments on this ... you would probably not shipping your own logging properties with the jar but instead leave it to the client (for example app-server, stage environment, etc) to configure the desired logging. Thus, putting it in src/test/resources is my preferred solution.
Note: Speaking of leaving the concrete log config to the client/user, you should consider replacing log4j with slf4j in your app.
Just putting it in src/main/resources will bundle it inside the artifact. E.g. if your artifact is a JAR, you will have the log4j.properties file inside it, losing its initial point of making logging configurable.
I usually put it in src/main/resources, and set it to be output to target like so:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>${project.build.directory}</targetPath>
<includes>
<include>log4j.properties</include>
</includes>
</resource>
</resources>
</build>
Additionally, in order for log4j to actually see it, you have to add the output directory to the class path.
If your artifact is an executable JAR, you probably used the maven-assembly-plugin to create it. Inside that plugin, you can add the current folder of the JAR to the class path by adding a Class-Path manifest entry like so:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.your-package.Main</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Now the log4j.properties file will be right next to your JAR file, independently configurable.
To run your application directly from Eclipse, add the resources directory to your classpath in your run configuration: Run->Run Configurations...->Java Application->New select the Classpath tab, select Advanced and browse to your src/resources directory.
Some "data mining" accounts for that src/main/resources is the typical place.
Results on Google Code Search:
src/main/resources/log4j.properties: 4877
src/main/java/log4j.properties: 215
The resources used for initializing the project are preferably put in src/main/resources folder. To enable loading of these resources during the build, one can simply add entries in the pom.xml in maven project as a build resource
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Other .properties files can also be kept in this folder used for initialization.
Filtering is set true if you want to have some variables in the properties files of resources folder and populate them from the profile filters properties files, which are kept in src/main/filters which is set as profiles but it is a different use case altogether. For now, you can ignore them.
This is a great resource maven resource plugins, it's useful, just browse through other sections too.
When putting resource files in another location is not the best solution you can use:
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<build>
For example when resources files (e.g. jaxb.properties) goes deep inside packages along with Java classes.
If your log4j.properties or log4j.xml file not found under src/main/resources use this PropertyConfigurator.configure("log4j.xml");
PropertyConfigurator.configure("log4j.xml");
Logger logger = LoggerFactory.getLogger(MyClass.class);
logger.error(message);
Add the below code from the resources tags in your pom.xml inside build tags.
so it means resources tags must be inside of build tags in your pom.xml
<build>
<resources>
<resource>
<directory>src/main/java/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<build/>

Categories