Gradle Project Resources Not Added to Classpath - java

I've been tasked with write some base classes for automated integration tests for an existing project, and I've run into a snag with project dependencies.
The (abstracted) project layout is this:
project /
MainProject
Plugins /
...
ConfigurationProject
IntegrationTestProject
IntegrationTestProject has a dependency upon ConfigurationProject, the latter having the following layout:
ConfigurationProject/
PluginConfigs/
<plugin configuration files>
<main configuration files>
Notably, the main configuration files reside in the root of the project. In an attempt to add them to my classpath, my primary build.gradle has the following:
project('ConfigurationProject') {
description = 'Configuration'
sourceSets.main.resources.srcDir projectDir
}
This seems to look okay, as eclipse shows all files in root as being part of the project resources, and assembling packages everything up as expected.
However, when I actually go to run the integration tests, the ConfigurationProject resources do not seem to be in the classpath, as it fails to pull config information, further confirmed by the lack of ConfigurationProject present in outputs from this snippet:
public void classpathScanner() {
ClassLoader c=getClass().getClassLoader();
System.out.println("c="+c);
URLClassLoader u=(URLClassLoader)c;
URL[] urls=u.getURLs();
for (URL i : urls) {
System.out.println("url: "+i);
}
}
The ConfigurationProject is included in IntegrationTestProject using the IntegrationTestProjects gradle.build
dependencies {
compile project(':ConfigurationProject')
}
I have only observed this problem when adding the project root as a resource, addng subfolders of a project to sourceSets seems fine (and is used elsewhere in this project). Moving the configuration files to a subfolder is an option I have considered, and will enact if I find no other solution, but I wanted to see if there were options that did not involve this course of action.

The answer to this is essentially "don't make project root a resource folder, Gradle hates that, and even if it didn't, it's bad form anyway" I fixed this by placing the configuration files to a more sensible resource path.

Related

Maven Plugin: Manipulate resources during packaging

in my maven project, I've got a xml file in resources. Depending on some input parameter I want the file to be adapted before packaged into a jar or war. Of course, the original file shall not be touched.
It is not an option to create multiple xml-files and select a suitable one, for example, with spring profiles as there can be numerous combinations of contents in the xml file.
So, I thought of creating a maven plugin, that manipulates the file before packaging. Probably, I need to manipulate the file, when maven has copied the file to the target folder but before maven packages the file into the jar/war.
#Mojo(name = "manipulate-xml", defaultPhase = LifecyclePhase.PREPARE_PACKAGE)
public class MyMojo extends AbstractMojo {
#Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;
#Parameter(property = "option")
String option;
public void execute() throws MojoExecutionException {
if (option.equals("optionA")) {
// get file from target and manipulate
} else if (option.equals("optionB")) {
// get file from target and manipulate
}
}
}
Then, I could embedded the maven plugin into my project and build the project with
mvn clean package -Doption=optionA
However, now I am stuck. I do not know, how to get the file from target and even if this is the right approach.
Besides, is it possible during the packaging to prevent some dependencies from being packaged into the jar/war?
I appreciate any help.
Depending on what manipulating means, you can use the possibilities of the maven resources plugin (https://maven.apache.org/plugins/maven-resources-plugin/index.html).
If you need to modify some simple values inside the xml, use properties in the xml and let the resources plugin replace them during build. The values for the build can be either in the pom.xml or given to maven via -Dproperty=value.
If you want to select a different files, define multiple maven profiles, in each you can configure the resources plugin to copy only the wanted files and then select the correct profile in the build.
If the built-in possibilities are not enough, you might even program your own filter for the resources plugin, that might be easier than writing a custom full fledged maven plugin.

Replace java platform system logger with slf4j in spring boot application

I've got a spring boot application build as multi-modular gradle project (old-style, not fancy jigsaw)
What I want to achieve - is replace java platform loggers (e.g., SSlLogger/ System.getLogger) with sl4j & logback that are used in my app and are managed by spring-boot-admin server at runtime. I need all my loggers to write to file instead of console - or else I won't see logs in Logz.io.
I do not control how my app is deployed, but I control the way fat jar is built (so, manuals with terminal commands 'java - ...' are not very helpful :( )
I started to follow https://www.baeldung.com/java-9-logging-api guide, but got stuck.
for simplicity, my structure is ->
build.gradle
/application-module
build.gradle (combines 3 other modules)
/src /...
/rest-module
build.gradle
/src /...
/service-module
build.gradle
/src /...
/persistency-module
build.gradle
/src /...
So, I want to add one more module
/log-module
/src -> with actual classes
module-info.java
Slf4jLogger implements System.Logger
Slf4jLoggerFinder extends System.LoggerFinder
and include it into my application-module
but when trying to build it all, I get 'error: module not found: org.slf4j', and app is not build.
So, what am I doing wrong? What additional plugins/config do I need? And will it even allow me to achieve my goal?
Okay, I managed to find the solution. It's a combination of
https://www.baeldung.com/java-9-logging-api
https://www.baeldung.com/java-spi
So, I don't even needed jigsaw modules - only the JDK's service provider mechanism
So, in fact you need 3 files [these are id's of pastebin's samples; but they are almost the same as in the java-9-logging-api article]
AkXY3zgu -> adapter class
YFUkZwat -> logger provider
CD6NNibj -> meta-inf file - and that's the trickiest part (with file name :) )
file name -> META_INF/services/java.lang.System$LoggerFinder
com.my-projects.commons.logs.Slf4jLoggerFinder
An now on regular app startup system logger will be replaced with slf4j-adapter.
But still, check how system logger is created -> for example, I mostly need SSLLogger, and there is some system-prop-based logic there...

Gradle with Eclipse - resources are not filtered

I have a gradle configuration setup to filter some resources and substitute properties depending on the environment (e.g. dev, production). These are located at:
src/main/resources/config.xml
WebContent/WEB-INF/web.xml
An example of a property from my web.xml file is below:
<context-param>
<param-name>server.url</param-name>
<param-value>${server_url}</param-value>
</context-param>
An excerpt from my build.gradle is presented below:
apply plugin: 'eclipse-wtp'
processResources {
expand(props) // filter properties by environment
exclude 'log4j.properties'
}
war {
from 'WebContent'
exclude('WEB-INF/web.xml')
webInf {
from 'WebContent/WEB-INF/web.xml'
expand(props)
}
webXml = null
}
This works fine when I build a war from the command-line, but when I use this configuration from Eclipse it does not seem to filter the resource appropriately.
I previously had the Maven plugin working where the resources would get filtered as a part of the Eclipse build. Is it possible to get Eclipse to filter the resources?
You should use webAppDirNameproperty for your project and remove the manuell stuff in war { ... } block. I am not sure which Gradle version introduced this property but at least 2.0. See also http://www.gradle.org/docs/current/userguide/war_plugin.html.
Afterwards gradle eclipse should generate proper Eclipse artifacts to build your war or directly deploy to any server using wtp!

Gradle tomcat plugin and properties files

I would like to use the gradle tomcat plugin in order to do integration tests with gradle. The current project relies on some .properties files underneath the running tomcat's catalina.base directory (cannot be changed because another dependent project relies on them as well).
Does anybody know how to deploy those files to the embedded tomcat instance?
I figured out it's just a simple copy task issue. Here's my solution:
task copyDMConfigFiles << {
def srcDir = new File('src/test/resources/conf')
if(!srcDir.isDirectory())
println "Outlet configuration files missing!!!"
def buildDir = new File('build/tmp/tomcatRunWar/conf')
if(!buildDir.isDirectory()) {
println "Outlet target directory missing. Creating one"
buildDir.mkdirs()
}
copy {
from(srcDir)
into(buildDir)
include '**/*.properties'
include '**/*.xml'
}
copy {
from('src/main/webapp/WEB-INF')
into('build/tmp/tomcatRunWar/work/Tomcat/localhost/digitalmedia/WEB-INF')
include 'web.xml'
include 'dispatcherservlet.xml'
}
}

Maven Assembly: config files best practice

I have a multi-module maven project, including a seperate assembly-project. As i develop and run my application from eclipse (during development), i have specific configuration-files (e.g. log4j or other property-files) in my main-module (which contains the main-class). These files contain development-time-specific information. The assembly-project contains each of the config-files for production. The assembled product then should use these configs instead. This is my current setup:
MainModule/src/main/resources
+configA.properties
+log4j.properties
Module1/src/main/resources
+configB.properties
AssemblyProj/src/main/resources
+configA.properties
+configB.properties
+log4j.properties
And the generated project has this structure:
libs/
+MainModule.jar
+Module1.jar
configs/
+configA.properties
+configB.properties
+log4j.properties
the config-directory overlays the config-files in each *.jar because of the classpath, i.e.
java -cp configs/;libs/* My.Main.Class
Now the problem that i have, is that there are still all dev-configs included in each jar. Also i have kind of a bad feeling about using that overlay-classpath-method. Is there any practice on how to do this in a better manner?
Extract these resources into classifier-based dependencies for each of the mentioned modules. Then define <profiles/> that trigger their usage. In your assembly use the classifiers as necessary.

Categories