FileNotFoundException resource file from external directory maven intellij - maven

I have some problem running SpringBoot application in Intellij. The #SpringBootApplication is located in the child module
└── conf
└── xml
└──beans.xml
└── source
└── core
└── common
└── MainApplication.java --> #SpringBootApplication
└── config
└── pom.xml --> parent
The MainApplication.java have annotation
#ImportResource("classpath:/beans.xml")
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages = {"com.xxx.yyy"})
#EnableCaching
#ImportResource("classpath:/beans.xml")
public class ServiceApplication extends SpringBootServletInitializer implements WebApplicationInitializer // extends SpringBootServletInitializer implements WebApplicationInitializer
{
The "config" module has pom.xml, no java file. It only generate the resources
<artifactId>config</artifactId>
<properties>
<environment>DEV</environment>
<country>ID</country>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<build>
<filters>
<filter>../../build/server.properties</filter>
</filters>
<resources>
<resource>
<directory>../../conf</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/**/log4j2.xml</exclude>
</excludes>
<targetPath>../../../../deploy/conf</targetPath>
</resource>
...
I tried to run configuration on Intellij, but it produce error FileNotFoundException for file beans.xml. This configuration already ran on Eclipse in other teammates. I want to run it on Intellij. I already import config module in Project Structure, and the conf folder already marked as Resource Root. Why its still not work? Or if I have to append change to existing java file or pom, its okay. as long the application can found its way to the resource folder. I dont need to build into war and run it, but I only want to run as SpringBoot application
Thank you. Any help will be appreciated.

i would say this is not a standard java project structure .... not good practice.
Go to File -> Project Structure -> Modules e.g.:
As you can see there u can edit the Paths to the Source, Resource, Test ... folders or add more than on.
perhaps this will help...

First: Remove the leading / from #ImportResource("classpath:/beans.xml").
This should be:
#ImportResource("classpath:beans.xml")
Second: Check that you beans.xml is copied to your project build directory when resources are processed.
The default location for the beans.xml would be target/classes/beans.xml.

Remove the leading / from #ImportResource("classpath:/beans.xml").
It should be like as : #ImportResource("classpath:beans.xml")
Check whether the source file beans.xml has been copied to the build directory or not:Path : /target/classess/beans.xml
If you have not placed the beans.xml in source folder, then provide the actual path or place it inside resource folder

Related

Is it possible to load Spring-Boot properties from config folder within parent module of a Maven multi-module project?

Is it possible to load multiple Spring-Boot .yml config files from a config folder within parent module of a multi-module project?
So, structure looks like this:
parent-module/
pom.xml
config/
application-prd.yml
application-dev.yml
module1
pom.xml
src/main/resources/
logback-spring.xml
bootstrap.yml
Is this possible? How can it be done?
So, if I execute from root folder of multi-module project, I would use this command:
mvn -pl module1 spring-boot:run
OR
mvn spring-boot:run
And I would hope that the config folder would be included in the classpath? I am trying to do this but not getting it to work. Am I missing something?
We know this to be true: Child POMs inherit properties, dependencies, and plugin configurations from the parent. But shouldn't that mean that {parent}/config/application.yml is in the classpath already?
Example project to use for proving: https://github.com/djangofan/spring-boot-maven-multi-module-example . Clone it and modify if you think you can solve it.
No need to write code. You can use Exec Maven Plugin for this. Add the plugin to the parent module:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>PACKAGE.MODULE_MAIN_CLASS</mainClass>
<arguments>
<argument>--spring.profiles.active=dev</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
then run mvn install once and then mvn exec whenever you want to start the application.
mvn exec:java -pl module1
For more on Maven goals in a multi-module project, check this answer https://stackoverflow.com/a/11091569/512667 .
Another way to configure this is like so, which requires the workingDirectory arg:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.Application</mainClass>
<workingDirectory>${maven.multiModuleProjectDirectory}</workingDirectory>
<arguments>
<argument>--spring.profiles.active=dev</argument>
</arguments>
</configuration>
</plugin>
In this case, execute:
mvn spring-boot:run -pl module1
Yes, it is possible.
Maven changes the working directory to the module's directory when you use the -pl. So it is no longer the root which has the config/ dir.
Either you can refactor your maven multi-module setup to a way that you can package the common application.yml files and than use them. I wouldn't recommend that as it has many pitfalls.
Probably easier to use the --spring.config-location
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
I can not test it at the moment but if it doesn't work you can always try the -Dspring.config.location or the SPRING_CONFIG_LOCATION environment variable.
I found a customized way of doing it, which I still consider to be a hack, as you can see below, but I am still looking for an actual answer to my question, if it exists.
#Slf4j
#SpringBootApplication
public class Application {
private static String DEV_PROPS = "application-dev.properties";
private static String PRD_PROPS = "application-prd.properties";
private static String DEFAULT_PROPS = "application.properties";
private static Path CONFIG = Paths.get(System.getProperty("user.dir"))
.resolve(Paths.get(".."))
.resolve("config");
private static final String EXT_CONFIG_DIR = CONFIG.toString() + File.separator;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new Resource[] {
new FileSystemResource(EXT_CONFIG_DIR + PRD_PROPS),
new FileSystemResource(EXT_CONFIG_DIR + DEV_PROPS),
new ClassPathResource(DEFAULT_PROPS)
};
log.info("Properties: " + Arrays.deepToString(resources));
properties.setIgnoreResourceNotFound(true);
properties.setLocations(resources);
return properties;
}
}
The problem with this method, is that configuration has to be changed to support additional environment profile names.

Spring Boot: Is it possible to separate css, js and template files from .war?

I have a new spring boot kotlin application deployed to live server by uploading the .war file created by Maven, it is working properly now. However, it seems that the static contents(css, js and template files) are also compressed in this .war file, this creates some issues for me as if I want to change the css on the live server, I have to re-deploy the entire .war file.
So I wonder, is it possible to separate the css/js/template files from the .war file? This way I upload the .war file to the server, and the css/js/template files separately. If I want to change the css or js file, I dont have to redeploy. Thanks, plz lemme know how this is possible.
You should be able to register resource locations outside your WAR, in order for Spring Boot to serve them.
For instance, you can serve all files from the /opt/files directory at the /files/<file_path_relative_to_optfiles_dir> URL this way:
#Configuration
#EnableWebMvc
class MvcConfig : WebMvcConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry
.addResourceHandler("/files/**")
.addResourceLocations("file:/opt/files/");
}
}
You can have more explanations in this Baeldung tutorial (it's in Java but you can get the idea).
You can use external resources configuration
If you don't want a file to be part of the war package, just put a simple configuration to exclude it:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.css</exclude>
</excludes>
</resource>
</resources>
</build>

How to include external configuration resources to classpath in Spring (Spring Boot)?

I have 3rd party library that is configured by placing properties file on the root of the classpath. That library is using getClass().getResourceAsStream("/file.properties") to load that file. As it is 3rd party, it is unmodifiable. I have placed that configuration file into external resources directory (not to be mistaken with resources from eg. Maven's or Gradle's directory structure.
Directory structure is like this.
How to run/configure Spring boot to include content of resources directory to the classpath so getResourceAsStream wil work?
On SE application I would simply do java -jar myApp.jar with classpath in MANIFEST and that would work.
EDIT:
Just a word of clarification - putting configuration file inside project resources (along sources) is missing the whole point. I want to keep configuration externalized.
Here is how you can do it:
1.- Change your spring-boot-maven-plugin configuration to enable the Spring Boot PropertiesLauncher:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layout>ZIP</layout>
</configuration>
</plugin>
</plugins>
</build>
2.- Launch your Spring Boot Application setting the location of the external properties file:
java -jar -Dloader.path=PATH_TO_PROPERTIES_FOLDER spring-ms-0.0.1-SNAPSHOT.jar
Assuming this folders:
/home/user/
|--- file.properties
|--- spring-mg-0.0.1-SNAPSHOT.jar
You should launch it like this: java -jar -Dloader.path=/home/user spring-ms-0.0.1-SNAPSHOT.jar

Jetty not looking in test-classes directory for resources

I am using maven-jetty plugin and when I use jetty to run a webapp, the webapp does not look in the target/test-classes directory at all for a resource. However, it can find resources in the target/classes directory.
Here is the relevant part of my pom.xml
<configuration>
<webApp>target/webapp.war</webApp>
<testClassesDirectory>target/test-classes/</testClassesDirectory>
<useTestClasspath>true</useTestClasspath>
<stopPort>9966</stopPort>
<stopKey>stopKey</stopKey>
</configuration>
How can I make the maven-jetty plugin look in target/test-classes for resources
Because /src/test/java and /src/test/resources folders are only intended for unit testing. They are not added to maven-jetty-plugin CLASSPATH nor they are included in resulting WAR.

How to add TLD and Tag Lib files into a Maven's jar project

I have a Maven project that is packaged as jar.
And I also have a Maven project that is packaged as war. This war project has a tld file and some xhtml files (the tag libs). The structure of the war project is (basically):
pom.xml
src
main
java
...
webapp
WEB-INF
my-facelets.taglib.xml
facelets
aTag.xhtml
anotherTag.xhtml
META-INF
my-facelets.taglib.tld
And then appeared a requirement to remove those xml, xhtml and tld files from the war project and package them into the jar project. So my first try was add in the jar project's POM:
<resources>
<resource>
<directory>src/main/tld</directory>
<targetPath>META-INF</targetPath>
</resource>
<resource>
<directory>src/main/taglib</directory>
<targetPath>WEB-INF</targetPath>
</resource>
</resources>
And put the files, of course, into src/main/tld (the ones I wanted to export into META-INF) and src/main/taglib (the ones I wanted to export into WEB-INF). And the jar was created as I wish:
myjar
com
my
classes
WEB-INF
META-INF
my-facelets.taglib.tld
WEB-INF
...
And then I added this new jar to my first war project, as a maven dependency.
The problem is that those .tld, .xhtml, .xml files that are inside the jar's META-INF, WEB-INF (the jar is inside war's WEB-INF/lib) are not recognized. Apparently they should be directly into the war structure, unless some other configuration is performed. This is a must-have requirement, because multiple war projects will use the features (classes and taglibs) of the jar project.
The practice these days is to put the TLD files into the tag library JAR and let the class loader find them. Download the Apache JSTL JARs and see how they do it. I'd recommend following that convention. It'll simplify your app too, because you won't have to declare the TLD in your web.xml file: just put the JAR in your CLASSPATH and make sure that the URI in your .jsp matches that in the TLD.
#duffymo - Your solution totally works. Adding graphic to your description.
Create a maven project that generates JAR. keep the structure like this below
src -- main
|-- java
| `-- net
| `-- madhur
| `-- helloTag.java
`-- resources
`-- META-INF
`-- tags
`-- customTags.tld
To your customTags.tld file add uri something like this
<uri>http://www.xyzabc.com/taglibs/customTags</uri>
Accessing tags in you WAR file
War should have following structure
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/lib/
WEB-INF/lib/{tagLibrary}.jar
WEB-INF/web.xml
WEB-INF/customTags.tld
web.xml
<jsp-config>
<taglib>
<taglib-uri>www.xyzabc.com/taglibs/customTags</taglib-uri>
<taglib-location>/WEB-INF/customTags.tld</taglib-location>
</taglib>
</jsp-config>
Using tag in FTL or JSP file
Ftl:
<#assign ct = JspTaglibs["www.xyzabc.com/taglibs/customTags"]>

Resources