Gradle exported properties dont work with gradle bootRun in Spring - java

in my Spring Boot project i have the following fragment in gradle which exports gradle properties to Spring Environment.
processResources {
filesMatching("**/application.properties") {
expand(project.properties)
}
}
My application.properties looks like this (snippet)
app.version=${jar.version}
Works pretty well. I can work with the gradle propeties in Spring classes with #value and even can access them in thymeleaf with
th:text="${#environment.getProperty('app.version')}
But now the issue: When i run the same project with "gradle bootRun". I am getting this:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'jar.version' in string value "${jar.version}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174) ~[spring-core-4.3.3.RELEASE.jar:4.3.3.RELEASE]
I assume its something about the way gradle's bootRun works by not using processResources or something like that?
The question would be: how can i get this to work. I dont want to give up using bootRun.

Specify a default value to use when the real one cannot be found?
#Value("${...:defaultValue}")

Related

Spring Boot DevTools being used inside docker container even after exclusion in gradle build

So we are using Spring boot to deliver our application. We use the Jib plugin to monitor create docker images and run them.
We use gradle to build the project and there dev tools is identified as a developmentOnly dependency.
Just as mentioned in the spring docs at https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-devtools .
However when it runs in the container in prod I still see it getting restarted now and then.
My question is does the gradle configuration not really exlude it from packaging.
Do i need to explicitly set the -Dspring.devtools.restart.enabled=false parameter ?
Solution :
So turns out it was the gradle jib plugin playing games.
While the spring documentation is spot on about how to go about removing the dependency from gradle spring boot project. The technique of specifying a developmentOnly only helps in telling gradle to ignore the dev tools. The jib gradle plugin has a mind of its own.
It includes all jars when building a docker image and there is no way to exclude any jar. The only reasonable way is to customize the gradle jib plugin in build.gradle to write this ,
jib {
from {
image 'gcr.io/distroless/java:11'
}
container {
jvmFlags = ['-Xms1G', '-Xmx1G', '-Dspring.devtools.restart.enabled = false']
}
}
This will make sure that even if the jar is included the container environment has the restart taken care of.
Reference : https://github.com/spring-projects/spring-boot/issues/15382
There's really a few problems here:
Springboot has its own custom definitions instead of using what would be the equivalent of profiles. Their approach is best for springboot users, but rather hard to integrate with given all their custom logic.
Jib can't know all the custom implementation of each framework.
I really think what you should be doing is something like this:
dependencies {
if (System.getProperty("development") == true) {
// include the springboot devtool dependency
}
}
When you want to run or build in dev mode, just do
./gradlew whateverTask -Ddevelopment=true
You can achieve that by setting spring.devtools.restart.enabled=false in your application.properties or your specific profile properties ex. application-cloud.properties. Let me know if this works.
Well, just faced the same problem recently and it seems there's already a very straight-forward way to solve it.
The problem
Jib is actually considering spring-boot-devtools as a runtime dependency and so, adding it to the image. In my case, this is also true for h2 database jar which is used only locally for development.
Also, I wouldn't like to deal with any extra custom parameter in my build, neither turn-off features by configuration if I don't really wanna them available at production.
Solution
GoogleContainerTools' team has released a jib-extension to deal with devtools problem directly. There's a Gradle and Maven version and it works flawlessly.
However, to my needs (also exclude h2) I've decided to use jib layer filter extension so I can keep my image as close to bootJar as possible.
Here goes the code snippet in gradle:
// should be at the top of build.gradle
buildscript {
dependencies {
classpath('com.google.cloud.tools:jib-layer-filter-extension-gradle:0.1.0')
}
}
jib {
// ...
pluginExtensions {
pluginExtension {
implementation = 'com.google.cloud.tools.jib.gradle.extension.layerfilter.JibLayerFilterExtension'
configuration {
filters {
filter {
glob = '**/h2-*.jar'
}
filter {
glob = '**/spring-boot-devtools-*.jar'
}
}
}
}
}
}
Check here the Gradle and Maven version for this extension.

Spring Boot Actuator doesn't read git.properties

I have a simple project with Spring Actuator, also i have a maven plugin generating git.properties (resides in classes directory).
However when i run my app, /actuator/info request shows:
{
"git": {}
}
Documentation says autoconfigure should pick up properties automatically https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-application-info-git
My mistake, git.properties was not a 'properties' file in fact.
I didn't see {} around a file content.
after changing configuration/format to properties in git-commit-id-plugin plugin, it works
(plugin was generating git info in json)

How to get version variable from build.gradle file into java spring boot controller?

I know how to get it if version is defined in application.properties, but how do I get it from build.gradle?
The general flow is:
Define a property in your application.properties that has placeholders, i.e. gradleVersion=${version}.
Configure Gradle's default task that copies your resource files out to the build directory (called processResources) to filter / expand those properties
Read in the gradleVersion property like any other Spring property
Note that it'll require you to invoke Gradle in order to properly resolve the gradleVersion property (as Gradle is the one putting the value in there). bootRun should already depend on processResources, so if you're using that you should be fine.

Getting the Gradle.build version into Spring Boot

I'm trying to display the application version of my Spring Boot application in a view. I'm sure I can access this version information, I just don't know how.
I tried following this information: https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html, and put this in my application.properties:
info.build.version=${version}
And then loading it #Value("${version.test}") in my controller, but that doesn't work, I only get errors like:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'version' in string value "${version}"
Any suggestions on what the proper way to get information like my app version, the spring boot version, etc into my controller?
You can also add this in build.gradle :
springBoot {
buildInfo()
}
Then, you can use BuildProperties bean :
#Autowired
private BuildProperties buildProperties;
And get the version with buildProperties.getVersion()
As described in the reference documentation, you need to instruct Gradle to process you application's resources so that it will replace the ${version} placeholder with the project's version:
processResources {
expand(project.properties)
}
To be safe, you may want to narrow things down so that only application.properties is processed:
processResources {
filesMatching('application.properties') {
expand(project.properties)
}
}
Now, assuming that your property is named info.build.version, it'll be available via #Value:
#Value("${info.build.version}")
I've resolved this by adding into application.yml the following:
${version?:unknown}
It also work from cli:gradle bootRun and also from IntelliJ and you don't have to call the Gradle task processResources before launching in IntelliJ or use spring profiles.
This work with Gradle ver:4.6 and also Spring Boot ver: 2.0.1.RELEASE.
Hope it helps ;)
I have solved it this way:
Define your info.build.version in application.properties:
info.build.version=whatever
use it in your component with
#Value("${info.build.version}")
private String version;
now add your version info to your build.gradle file like this:
version = '0.0.2-SNAPSHOT'
then add a method to replace your application.properties with a regex to update your version information there:
def updateApplicationProperties() {
def configFile = new File('src/main/resources/application.properties')
println "updating version to '${version}' in ${configFile}"
String configContent = configFile.getText('UTF-8')
configContent = configContent.replaceAll(/info\.build\.version=.*/, "info.build.version=${version}")
configFile.write(configContent, 'UTF-8')
}
finally, ensure the method is called when you trigger build or bootRun:
allprojects {
updateVersion()
}
that's it. This solution works if you let Gradle compile your app as well as if you run your Spring Boot app from the IDE. The value will not get updated but won't throw an exception and as soon as you run Gradle it will be updated again.
I hope this helps others as well as it solved the problem for me. I couldn't find a more proper solution so I scripted it by myself.
For Kotlin user, what works for me was :
application.properties
In the application.properties you add a placeholder that will be replace with your value by gradle.
project.version= ${version}
build.gradle.kts
Add a task so gradle will replace the value
tasks.processResources { filesMatching("**/application.properties") { expand(project.properties) } }
Service.kt
Inject the value in your services
#Value("\${project.version}") lateinit var version: String

Overriding web.xml context params

I have a maven project that I am migrating to gradle. In the maven project I use the jetty plugin and provide an overrideDescriptor like this:
<webAppConfig>
<overrideDescriptor>override.xml</overrideDescriptor>
</webAppConfig>
Using this, I can override some context parameters from my web.xml with parameters from the override.xml, but any parameters not in the override.xml will revert to the value in the web.xml. This all works as expected.
Now that I am moving to gradle, I am trying to replicate this using the gradle jetty plugin. I tried providing a webXml value, but it replaces the entire web.xml file:
jettyRun {
webXml file('override.xml')
}
Is there any way I can provide the same override functionality via gradle, or am I stuck reworking my override file to be a complete replacement for my default web.xml.
Try overrideWebXml, e.g.:
jettyRun {
overrideWebXml file('override.xml')
}
This is a property on AbstractJettyRunTask, and worked for me.
This would be entirely within the gradle plugin so best to check the documentation for the plugin to see if there is an override option. If not it ought to be relatively easy to add it and contribute back to that project.

Categories

Resources