Using Spring DSL in a Grails Plugin - spring

I'm trying to use the Spring DSL functionality in a Grails plugin. However, it doesn't work. Here's what I have in my plugin's conf/spring/resources.groovy file:
import org.springframework.aop.scope.ScopedProxyFactoryBean
// Place your Spring DSL code here
beans = {
baseSvcProxy(ScopedProxyFactoryBean) {
targetBeanName = 'baseService'
proxyTargetClass = true
}
}
However, it seems to be completely ignored. If I move the exact same code to the application's conf/spring/resources.groovy file everything works perfectly. Is there something that needs to be done differently for plugins for this to work?

In order to modify the spring context from a Grails plugin you need to use the doWithSpring section of your plugin by hooking into the runtime configuration. Resources.groovy is ignored in plugins.

Related

Custom Configuration dependency declaration

I am trying to convert build.gradle to kotlin dsl. Using gradle 7.4.1.What the right way to declare custom configuration. For custom configuration like
configurations { grafana }
sourceSets { grafana }
and within dependencies block
grafanaImplementation "org.slf4j:slf4j-simple:1.7.36"
grafanaImplementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
grafanaRuntimeOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
While I am in kotlin-dsl I am doing
val grafana by configurations.creating
val grafanaSourceSet = sourceSets.create("grafana")
and within dependency block
grafana("org.slf4j:slf4j-simple:1.7.36")
grafana("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
When I try to put grafanaImplementation/ grafanaRuntimeOnly within kotlin dsl, it fails.
What is the equivalent of grafanaImplementation/ grafanaRuntimeOnly within kotlin dsl
Quick fix
When you do
val grafanaSourceSet = sourceSets.create("grafana")
behind the scenes Gradle will create the required configurations, grafanaImplementation, grafanaRuntimeOnly, etc, so you can use them without error like this:
val grafanaSourceSet = sourceSets.create("grafana")
dependencies {
"grafanaImplementation"("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
"grafanaRuntimeOnly"("org.slf4j:slf4j-simple:1.7.36")
}
This approach is more like how Groovy works - it basically disables type-checking and the strings will be evaluated during Gradle execution.
Generated DSL accessors
However, string-typing is not why we like Kotlin! We want type-safety and auto completion hints. That's exactly what we see with the implementation() and runtimeOnly(). So how do we get them for grafanaImplementation() and grafanaRuntimeOnly()?
Basically, Gradle will scan the registered config and when it sees that a plugin creates an implementation configuration, it generates Kotlin DSL accessors. However, it can't generate accessors for the build.gradle.kts that contains the definition for the accessors... that's too late. So we need to define the config earlier. We can do that with a buildSrc plugin.
buildSrc Grafana convention plugin
Set up a buildSrc project (this is covered more in the Gradle docs or other StackOverflow answers)
Create a pre-compiled script plugin for Grafana config
// $projectRoot/buildSrc/src/main/kotlin/grafana.convention.gradle.kts
plugins {
// using 'sourceSets' requires the Java plugin, so we must apply it
java
}
val grafanaSourceSet = sourceSets.create("grafana")
Note that this convention plugin is quite opinionated as it applies the Java plugin. In more complex setups you might want to instead react to the Java plugin, rather than always applying it.
Now apply the convention plugin, and Gradle will generate the Kotlin DSL accessors!
// $projectRoot/build.gradle.kts
plugins {
id("grafana.convention")
}
dependencies {
// no string-typing needed!
grafanaImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
grafanaRuntimeOnly("org.slf4j:slf4j-simple:1.7.36")
}

How to configure netflix dgs?

This is a really simple question, but hard to find the answer.
I'm using kotlin DSL and gradle (so build.gradle.kts and settings.gradle.kts).
I'm using netflix-dgs and spring boot like so:
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.netflix.graphql.dgs:graphql-dgs-spring-boot-starter")
And of course a few others (e.g. extended scalars).
I've figured out how to edit my generateJava task:
tasks.withType<com.netflix.graphql.dgs.codegen.gradle.GenerateJavaTask> {
schemaPaths = mutableListOf("$projectDir/src/main/resources/schema")
packageName = "envoy.roomba.netflix.dgs.generated"
}
How do I edit the rest of the configuration mentioned here? https://netflix.github.io/dgs/configuration/.
I tried a gradle.properties file, I've looked briefly at extending #DgsAutoConfiguration, but without any luck.
you can configure properties in the applciation.yml file or application.properties whatever is relevant in your case. Since you are using spring boot, DGS will pick up properties from your application properties file.

Primitive Axon App run as Fat JAR Doesn't Autoconfigure Axon Beans

PROBLEM:
RESEARCH: At https://gitlab.com/ZonZonZon/simple-axon.git I've made up a simple Axon-app to show that JAR-artifact built with Gradle-plugin com.github.johnrengelman.shadow doesn't autoconfigure Axon beans when (when run as JAR). Though it runs fine under Intellij.
From project root in terminal:
run gradle clean build shadowJar;
java -jar build/simpleaxon.jar;
Stacktrace is enclosed here. I expect that Axon Autocongiguration provides beans like CommandBus, Snapshotter and other by default.
QUESTION: How to autoconfigure default axon beans in a fat jar?
So, this took my some investigation to get a hunch what is going wrong, but I know what the problem is.
Quick notice, it's not an Axon specific thing, rather the plugin you are using.
I ran your sample project and indeed ended up with the same result; no Axon beans were being wired, ever. That led me to investigate the process of creating fat JAR's step by step. First Maven, then Spring Boot with Maven, then Gradle with Spring Boot and finally with the Shadow plugin you are referring too.
This endeavour landed me on this issue, which states as much as "projects which require the use of META-INF files need to add this to the shadow plugin, and this should be documented".
The portion referenced through this is the following:
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
// Left out all other specifics from your 'build.gradle' file
shadowJar {
// Required for Spring
mergeServiceFiles()
append 'META-INF/spring.handlers'
append 'META-INF/spring.schemas'
append 'META-INF/spring.tooling'
transform(PropertiesFileTransformer) {
paths = ['META-INF/spring.factories' ]
mergeStrategy = "append"
}
setArchiveFileName("simpleaxon.jar")
getDestinationDirectory().set(new File(projectDir, "./build"))
}
After adding that piece of logic to your build.gradle file, I could run your sample project as expected.
I've hit a similar issue when using Axon in a multimodule Gradle project. The app would not work when packaged and worked fine in IDE. The exact error I was getting was
org.axonframework.messaging.annotation.UnsupportedHandlerException: Unable to resolve parameter 0 in handler
The reason for this was because ParameterResolverFactories were not loaded due to the META-INF/services resources not being resolved correctly in the shadow jar plugin as #Steven hinted.
I've managed to fix it with simply (using Kotlin DSL in Gradle):
tasks.shadowJar {
mergeServiceFiles()
}
#Steven 's solution was the only one working for me, after searching for a long time for other solutions.
The Gradle Kotlin Version looks like this https://github.com/spring-projects/spring-boot/issues/1828#issuecomment-607352468:
import com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer
plugins {
id("com.github.johnrengelman.shadow") version "7.1.2"
}
...
tasks.shadowJar {
// Required for Spring.
// The shadowJar plugin should merge the services correctly, but it doesn't!
mergeServiceFiles()
append("META-INF/spring.handlers")
append("META-INF/spring.schemas")
append("META-INF/spring.tooling")
transform(
PropertiesFileTransformer().apply {
paths = mutableListOf("META-INF/spring.factories")
mergeStrategy = "append"
})
}

Custom properties in Spring Boot project using Gradle

In my Spring Boot project (1.5.6.RELEASE) that I build using gradle, I want to include some custom properties. The approach laid out in the documentation does not seem to work (on build, I get: Could not set unknown property 'additional' for task ':properties' of type org.gradle.api.tasks.diagnostics.PropertyReportTask.):
springBoot {
buildInfo {
properties {
additional = [
'a': 'alpha',
'b': 'bravo'
]
}
}
}
Luckily this approach, which I found here, does work for me (no compile error and I'm then able to access the property from my code):
springBoot{
buildInfo {
additionalProperties = [
'testpropertykey': 'testpropertyvalue'
]
}
}
But, since the former is the "officially" documented approach, I would prefer to take that approach. How would I get the former approach to work? I assume I'm missing something - unless the documentation is wrong or maybe this changed from Spring Boot 1.5.6.RELEASE.
The docs you linked are for the current version of the plugin which aligns with the current GA version of Spring Boot: 2.1.7
Version 1.5.x of the plugin does have a additionalProperties field: https://github.com/spring-projects/spring-boot/blob/1.5.x/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/buildinfo/BuildInfo.java#L66
The 2.1.x version does not and you use properties instead: https://github.com/spring-projects/spring-boot/blob/2.1.x/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.java#L45
Suggest you migrate/upgrade to Spring Boot 2.1.x or 2.2.x when that is released soon since 1.5.x has already reached EOL: https://spring.io/blog/2018/07/30/spring-boot-1-x-eol-aug-1st-2019

How to remove a dependency in Gradle depending on the Spring Boot runtime environment?

Not sure if this is a Gradle question or a Spring Boot one, but here goes...
I am using Spring security and LDAP in a spring boot application.
I have the following dependencies in my build.gradle:
compile 'org.springframework.security:spring-security-ldap:3.2.4.RELEASE'
compile 'org.apache.directory.server:apacheds-server-jndi:1.5.5'
The second of these supplies an embedded LDAP server that is only needed during development.
I have established a SB #Profile and configure/load an LDIF file into the embedded server within a class that has the #Profile('development') annotation.
The question is: how to remove the second dependency when not in dev mode?
I establish the spring.profiles.active property within my config/application.yml file, thusly:
spring:
profiles:
active: development
Can I reference spring.profiles.active so that I can somehow exclude the unneeded dependency?
For posterity, what I ended up doing...
At the top of my build.grade file:
def readActiveProfile() {
final config = new org.yaml.snakeyaml.Yaml().loadAll(new File('config/application.yml').newReader())
final defaultPart = config?.take(1)
defaultPart?.spring?.profiles?.active
}
final activeProfile = readActiveProfile() ?: ['development']
This reads the config file that I am keeping my externalised settings in (one of which is the setting defining the active profile).
And then, in the dependencies section:
compile 'org.springframework.security:spring-security-ldap:3.2.4.RELEASE'
if( ! ('production' in activeProfile))
compile 'org.apache.directory.server:apacheds-server-jndi:1.5.5'
This works well enough for my purposes, but doesn't feel quite right; I was assuming that there would be a more idiomatic "Gradle way" of doing this.

Resources