How to change contents of .properties in Gradle upon war creation - java

I'm experimenting with Gradle's war plugin. At this point project is still using Ant. Its a standard webapp layout:
| - project
| ---- src/main/java
| ---- src/main/resource
| ---- src/main/webapp
| ---- src/main/webapp/WEB-INF/classes
In src/main/webapp/WEB-INF/classes there's a properties file containing key jawr.debug.on. For development purposes, it is usually set to true. During release phase this property is changed to false using Ant's propertyfile task.
I'm unable to find similar way of performing this in Gradle. I did find snippet below, but its not changing said file inside the resulting war:
ant.propertyfile(
file: "jawr.properties") {
entry( key: "jawr.debug.on", value: "false")
}
What would be the proper way to achieve this?

One way would be to filter it during war creation
war {
rootSpec.eachFile {
if (it.name == 'UserMessages.properties') {
filter { line ->
line.replace('#build.label#', "${buildLabel}-${stage}")
}
}
}
}

Related

Log4j2 environment variables are not applied

My project depends on a jar that (among other things I need) includes common logging configurations for a number of projects. I can update the jar, but I can't break compatibility with existing consumers. The jar contains:
src
|-- main/resources
| |-- log4j2-bad.xml // not actually named `-bad` but a config I want to overwrite for a unique use case without losing the other classes in the jar
| `-- log4j2.component.properties //contents=`log4j2.configurationFile=log4j2-bad.xml,log4j2.xml`
`-- test/resources
`-- log4j.xml // normally the consumer provides their own `log4j2.xml` file.
I want to provide an opt-in alternative file (e.g. log4j2-good.xml) in src/main/resources. Since the documentation says that environment variables (and specifically LOG4J_CONFIGURATION_FILE) should take precedence over log4j2.component.properties, it seems like I could just add log4j2-good.xml to the jar, and consumers that want to opt-in could arrange for the LOG4J_CONFIGURATION_FILE environment variable to be log4j2-good.xml,log2j2.xml at runtime.
However, this does not seem to work.
I added a Main class to the jar for testing. It contains some logging statements and this static block:
static {
System.out.println("LOG4J_CONFIGURATION_FILE: " + System.getenv().get("LOG4J_CONFIGURATION_FILE"));
}
When I set $env:LOG4J_CONFIGURATION_FILE=log4j2-good.xml,log4j2.xml and run it, I get:
2021-11-17 21:39:32,091 main DEBUG Apache Log4j Core 2.14.1 initializing configuration org.apache.logging.log4j.core.config.composite.CompositeConfiguration#6ee52dcd [configurations=[XmlConfiguration[location=C:\<snip>\bin\main\log4j2-bad.xml], XmlConfiguration[location=C:\<snip>\bin\test\log4j2.xml]], mergeStrategy=org.apache.logging.log4j.core.config.composite.DefaultMergeStrategy#4493d195, rootNode=null, listeners=[org.apache.logging.log4j.core.LoggerContext#2781e022], pluginPackages=[], pluginManager=org.apache.logging.log4j.core.config.plugins.util.PluginManager#57e1b0c, isShutdownHookEnabled=true, shutdownTimeoutMillis=0, scriptManager=null]
<snip>
LOG4J_CONFIGURATION_FILE: log4j2-good.xml,log4j2.xml
So log4j2 uses the bad config, but my Main says the environment variable specifies the good config.
When I open Windows system properties and set the system environment variable...same thing.
When I run a gradle task:
task runGoodConfig(type: JavaExec) {
classpath = sourceSets.test.runtimeClasspath
main = 'com.my.sample.Main'
environment(['LOG4J_CONFIGURATION_FILE':'log4j2-good.xml,log4j2.xml'])
}
same result.
What am I missing!?
This is a confirmed bug in version 2.14.1 (at least).

custom maven archetype: default value for version not used

In my maven archetype definition, I would like to set the default version to 0.0.1-SNAPSHOT when the user doesnt enter anything. However, when I create a project based on the archetype, I am always prompted for the version and the default is 1.0-SNAPSHOT.
How do I do this correctly?
I defined a version property in the archetype.properties file and when I compile the archetype, it says the correct version and when I change the value in the archetype.properties, I can see that the console output changes accordingly.
Just on creating a project based on the archetype, I get prompted for the version again.
Thanks for help and tips!
(I'll provide code if necessary)
You can define custom properties in you archetype metadata. Have a look at the archetype-metadata.xml in META-INF/maven. For example:
my-archetype
|
+ src
|
+ main
|
+ resources
|
+ META-INF
|
+ maven
|
+ archetype-metadata.xml
A custom property for version would look like this:
<?xml version="1.0" encoding="UTF-8"?>
<archetype-descriptor name="basic">
<requiredProperties>
<requiredProperty key="version">
<defaultValue>0.0.1-SNAPSHOT</defaultValue>
</requiredProperty>
</requiredProperties>
</archetype-descriptor>
More details in the docs.
When you run the mvn archetype:generate command referencing an archetype with the above configuration you'll see this in the console output:
[INFO] Using property: version = 0.0.1-SNAPSHOT
Or, if you run the mvn archetype:generate command with the parameter -Dversion=FOO then you'll see this in the console output:
[INFO] Using property: version = FOO
Note: this version is, of course, separate from the archetypeVersion which defines the version of the archetype itself rather than the version of the module produced by the archetype.

Spring Boot application with part of JSP files from other Maven module

Let's assume that we have Spring Boot based web application using JSP templates. It can be even as simple as in the following example (from official Spring Projects repository)
Project structure:
|-src/main/java/
| |-sample.tomcat.jsp
| |-SampleTomcatJspApplication.java
| |-WelcomeController.java
|-src/main/resources/
| |-application.properties
|-src/test/java/
| |-...
|-src/main/webapp/
| |-WEB-INF
| |-jsp
| |-welcome.jsp
|-pom.xml
Properties file contains view prefix /WEB-INF/jsp/ and suffix .jsp and when requesting / we see properly rendered content of welcome.jsp.
WelcomeController.java
application.properties
Changes
Now let's make the following changes
Duplicate WelcomeController.java as WelcomeController2.java and change a bit request mapping, model attributes and returned view name, e.g.:
#RequestMapping("/2")
public String welcome2(Map<String, Object> model) {
model.put("message", "Hi from Welcome2");
return "welcome2";
}
Duplicate welcome.jsp as welcome2.jsp so that src/main/webapp will be like this:
|-src/main/java/
| |-sample.tomcat.jsp
| |-SampleTomcatJspApplication.java
| |-WelcomeController.java
| |-WelcomeController2.java
...
|-src/main/webapp/
| |-WEB-INF
| |-jsp
| |-welcome.jsp
| |-welcome2.jsp
Then when requesting /2 we can see properly rendered content of welcome2.jsp.
The question
What is the way of splitting such project into two maven projects, so that both WelcomeController2.java and welcome2.jsp could be moved to other project (maven dependency) and still be successfully resolved when /2 URL is requested?
Note that with Spring Boot web-fragment.xml (that could be placed in META-INF directory of dependency) is ignored.
Unfortunately, I don't know of an easy way to do this but one approach I've used is to create a Maven artifact just like normal for the main project, in your case probably a WAR artifact. This project will need to have a dependency upon your second project. Then your second project would consist of two components:
A standard Maven JAR artifact containing the compiled class files.
A Maven assembly ZIP consisting of the JSP files that need to be included in the WAR archive as well. This will be generated from the second project during the package phase, but will need to be included as a separate dependency on the main project using a zip classifier.
When the first project is built, you'll need to unpack the assembly dependency as part of the packaging process for the WAR archive. If you want this to work in an IDE, you'll probably need to unpack it in a fairly early phase, such as process-resources or generate-sources.

build.sbt configuration to add external java files using sbt packageSrc

I am using sbt-xjc plugin to generate java classes from XSD files. The plugin generates these classes under project/target/scala-2.10/xjc directory.
I need to create 2 jar files one with all .class files and another with all .java source files.
I am able to generate the jar file that has all .class files using sbt package but the issue is with sbt packageSrc, this command is looking only for folder those are in project/src/java folder and not considering files those are generated by sbt-xjc plugin under project/target/scala-2.10/xjc. Is there any configuration that i can provide that could help?
To know why this happens the command inspect tree packageSrc is helpful, it will also tell you what to change to have your sources included.
When executed should show you something like this:
> inspect tree packageSrc
[info] compile:packageSrc = Task[java.io.File]
[info] +-compile:packageSrc::packageConfiguration = Task[sbt.Package$Configuration]
[info] | +-compile:packageSrc::mappings = Task[scala.collection.Seq[scala.Tuple2[java.io.File, java.lang.String]]]
[info] | | +-compile:unmanagedSources = Task[scala.collection.Seq[java.io.File]]
[info] | | +-compile:unmanagedResources = Task[scala.collection.Seq[java.io.File]]
[info] | | +-compile:unmanagedResourceDirectories = List(/tmp/q-23437043/src/main/resources)
[info] | | +-*:baseDirectory = /tmp/q-23437043
[info] | | +-compile:unmanagedSourceDirectories = List(/tmp/q-23437043/src/main/scala, /tmp/q-23437043/src/main/java)
// more stuff but not relevant for us
You can see from there that SBT is using mappings key to know from where to take the files.
Knowing that we can take the generated files and add them to the mappings in packageSrc in your build.sbt:
import Path.flat
xjcSettings
def xjcSources(base: File) = base ** "*"
mappings in Compile in packageSrc ++= xjcSources((sourceManaged in (Compile, xjc)).value) pair flat
You can read more about Mappings and Paths to customize / control the result.

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'
}
}

Categories