How to use AspectJ with Grails 3 - gradle

I would like to use AspectJ in my Grails 3.3.6 application. Spring AOP works very well but I need to use call pointcut designator which is not supported by Spring AOP.
This is my aspect file which is located under src/main/java
TestAspect.aj
public aspect TestAspect{
pointcut executeMethod(): call(* com.example..*.*(..));
before(): executeMethod(){
System.out.println("before " +thisEnclosingJoinPointStaticPart.getSignature().getName());
}
after(): executeMethod(){
System.out.println("after "+thisJoinPoint.getSignature().getName());
}
}
I tried gradle aspectj plugin and updated build.gradle as follows
build.gradle
buildscript {
repositories {
...
}
dependencies {
classpath "gradle.plugin.aspectj:gradle-aspectj:0.1.6"
}
}
project.ext {
aspectjVersion = '1.9.1'
}
apply plugin:"java"
apply plugin: 'aspectj.gradle'
Application starts without any errors but my aspect is not working. Am I missing something ?
Using IntelliJ 2018.2.1 and Java 1.8.0_171
Thanks in advance

Related

Error while trying to get build script read the java file - Could not resolve all artifacts for configuration ':classpath'

I'm trying to follow this by adding my own custom java file into the classpath
https://github.com/gigaSproule/swagger-gradle-plugin#model-converters
This is shown in the example above
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.custom:model-converter:1.0.0'
}
}
...
swagger {
apiSource {
...
modelConverters = [ 'com.custom.model.Converter' ]
}
}
This is my code
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.test.app.profile.component.MyOpenApiCustomiser:1.0.0")
}
}
swagger {
apiSource {
...
modelConverters = [ 'com.test.app.profile.component.MyOpenApiCustomiser' ]
}
}
This is the error I'm getting
A problem occurred configuring root project 'profile'.
> Could not resolve all artifacts for configuration ':classpath'.
> Could not find com.test.app.profile.component.MyOpenApiCustomiser:1.0.0:.
Required by:
project :
Possible solution:
- Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html
I tried removing 1.0.0
Caused by: org.gradle.api.IllegalDependencyNotation: Supplied String module notation 'com.test.app.profile.component.MyOpenApiCustomiser' is invalid. Example notations: 'org.gradle:gradle-core:2.2', 'org.mockito:mockito-core:1.9.5:javadoc'
Not sure how I would get my build script to the use the MyOpenApiCustomiser in my spring boot application
Is there any other way or how to fix this?
The classpath dependency given in the buildscript.dependencies {} block needs to be a external library, given in the standard group:modulde:version notation; in the example from github project it's "com.custom : model-converter : 1.0.0" ( it's a "fake" library, does not really exist in maven central repo, it's just an example)
In your case, it seems you try to refer your class MyOpenApiCustomiser as the classpath library , which cannot work. It needs to be a real library.
If you want to use your own Converter, you'll need to implement it in another library/module, publish it to a private repository and then consume it in your buildscript classpath.
Another simpler way, would be to implement this converter as a class within the buildSrc project: these classes will then be automatically available in your build script classpath, and you can use it in the apiSource configuration.
Sample:
In your buildSrc project
build.gradle
plugins {
id("java")
}
repositories {
mavenCentral()
}
dependencies {
implementation "io.swagger:swagger-core:1.6.2"
}
Your custom ModelConverter class goes under src/main/java, e.g. com.sample.MyCustomConverter
In your root build.gradle script:
You can reference your MyCustomConverter class, it's already available in the script classpath, no need to define a classpath dependency in buildscript
swagger {
apiSource {
modelConverters = [ 'com.sample.MyCustomConverter' ]
// ....

How to override a plugin dependency in a Gradle conventions plugin

I'm using Gradle's conventions as described here:
https://docs.gradle.org/current/samples/sample_convention_plugins.html
And in the convention plugin, I'm applying a plugin (io.freefair.gradle:lombok-plugin:6.5.1) however I now need to override a dependency that it uses (I need org.projectlombok:lombok:1.18.22 not 1.18.24)
I've tried this:
buildscript {
dependencies {
classpath 'org.projectlombok:lombok:1.18.22'
}
}
plugins {
id 'groovy-gradle-plugin'
}
...
dependencies {
implementation 'io.freefair.gradle:lombok-plugin:6.5.1'
...
implementation 'org.projectlombok:lombok:1.18.22'
}
But version 1.18.24 was used. I've also tried adding this to my build.gradle:
buildscript {
dependencies {
classpath 'org.projectlombok:lombok:1.18.22'
}
}
plugins {
id 'billforward.java-conventions'
}
but still 1.18.24 was used.
As an aside, the two underlying issues I'm trying to solve are:
https://github.com/freefair/gradle-plugins/issues/549 - Resolved in 6.5 of lombok-plugin
https://github.com/projectlombok/lombok/issues/3180 - Broken in 1.18.24 of lombok
The lombok version used by io.freefair.lombok can be customized by using the lombok extension property:
plugins {
id "io.freefair.lombok" version "6.5.1"
}
lombok.version = "1.18.22"
This is documented here: https://docs.freefair.io/gradle-plugins/6.5.1/reference/#_io_freefair_lombok_base
Adding lombok itself to the buildscript classpath (or the runtime classpath of your gradle plugin) will not do anything.

IntelliJ does not pick up own spring configuration metadata

I'm having problems for IntelliJ to pickup custom spring configuration metadata with Gradle.
If I create a new Spring Boot project with the Initializer, include the Configuration Processor in the dependencies, on the Gradle task set the following tasks,
create a class with the content:
package com.example.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Component
#ConfigurationProperties("mycustomconfig")
public class MyCustomConfig {
private String name;
public String getName() {
return name;
}
public MyCustomConfig setName(String name) {
this.name = name;
return this;
}
}
then IntelliJ complains in the class file "Spring Boot Configuration Annotation Processor not found in classpath", even though it is definitely on the classpath.
After running the application, there is a file generated in build/classes/java/main/META-INF/spring-configuration-metadata.json with the following content:
{
"groups": [
{
"name": "mycustomconfig",
"type": "com.example.demo.MyCustomConfig",
"sourceType": "com.example.demo.MyCustomConfig"
}
],
"properties": [
{
"name": "mycustomconfig.name",
"type": "java.lang.String",
"sourceType": "com.example.demo.MyCustomConfig"
}
],
"hints": []
}
But IntelliJ then complains in application.properties: Cannot resolve configuration property "mycustomconfig.name".
The same experiment works flawlessly with Maven. Is there anything I'm doing wrong?
I'm using IntelliJ 2018.3 Ultimate.
My build.gradle is:
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Finally, I've found the cause of the issue.
The annotation processor outputs the spring-configuration-metadata.json to build/classes/java/main/META-INF`.
But: IntelliJ uses a different classpath for the resolvement. Going to Project structure/Modules/main module/Paths, you can see that for the compiler output is set to "use module compile output path" and points to out/production/classes. This is resolved from Gradle automatically; changing it will be reverted once you have any changes in Gradle.
I've found that there are two possibilites:
Configure the Spring Boot Annotation Processor manually in IntelliJ Preferences/Build, Execution, Deployment/Compiler/Annotation Processors, with the following settings:
This has the benefit, that you do not need to run a complete gradle build - Just compiling from IntelliJ works. Unfortunately, every user in the project seems to manually set this up.
The second possiblity is mentioned at at this Stack overflow question. Set this idea options in Gradle:
idea{
module{
inheritOutputDirs = false
outputDir = compileJava.destinationDir
testOutputDir = compileTestJava.destinationDir
}
}
This basically now uses one compiled target class both for IntelliJ as well as Gradle. There seem to be some caveats, though, as mentioned in the linked urls.
Not sure if you solved this but I just upgraded to 2018.3 Ultimate and ran into the same problem. I suspect it is an IntelliJ issue but regardless I solved it by adding the following line
implementation('org.springframework.boot:spring-boot-configuration-processor')
Just above the "annotationProcessor" line in my gradle file...
Hope that helps
If you are using Maven, adding this dependency would resolve the issue.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

Spring Boot / Security classloader issues with Keycloak run from terminal

I use Spring Boot and Spring Security in combination with Keycloak. The build tool is gradle.
When I run ./gradlew bootRun the application works flawless. If I use the resulting fat jar (i.e. java -jar myapp.jar) the application will boot but I encounter an exception when the application tries to invoke some keyloak stuff:
java.lang.IllegalArgumentException: org.keycloak.admin.client.resource.RealmsResource referenced from a method is not visible from class loader
at java.base/java.lang.reflect.Proxy$ProxyBuilder.ensureVisible(Proxy.java:851) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.validateProxyInterfaces(Proxy.java:682) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:628) ~[na:na]
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$1(Proxy.java:426) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203) ~[na:na]
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:424) ~[na:na]
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:999) ~[na:na]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.proxy(ProxyBuilder.java:79) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.build(ProxyBuilder.java:131) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.proxy(ClientWebTarget.java:93) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.keycloak.admin.client.Keycloak.realms(Keycloak.java:114) ~[keycloak-admin-client-3.4.3.Final.jar!/:3.4.3.Final]
at org.keycloak.admin.client.Keycloak.realm(Keycloak.java:118) ~[keycloak-admin-client-3.4.3.Final.jar!/:3.4.3.Final]
So I figured out that there must be something wrong how I start the application in the terminal. I found this official site, which explains how to run an Spring application from terminal. So I tried all of the solutions including:
$ unzip -q myapp.jar
$ java org.springframework.boot.loader.JarLauncher
but I get the same error.
After 2 days of searching and experimenting I'm out of any ideas.
So my question is basically:
Does anyone have any idea how to solve this problem?
My knowledge regarding the classloader is also limited - so any pratical hints in this direction are very welcomed as well.
EDIT (added build.gradle):
There were some Jackson problems that's why the Spring web dependencies are included directly (without the starter and therefor without Jackson).
Here is the build.gradle:
buildscript {
ext {
kotlinVersion = '1.2.20'
springBootVersion = '1.5.7.RELEASE'
keycloakVersion = '3.4.3.Final'
restEasyClientVersion = '3.1.4.Final'
postgresServerVersion = '10.0'
postgresJdbcDriverVersion = '42.1.4'
spekVersion = '1.1.5'
jacksonVersion = '2.8.10'
javaxWsRsVersion = '2.1'
logbackVersion = '1.2.3'
slf4jVersion = '1.7.25'
}
repositories {
mavenCentral()
jcenter()
//spring dev
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
//Kotlin dev
maven { url 'http://dl.bintray.com/kotlin/kotlin-eap-1.2' }
//gradle plugins
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}")
classpath('com.bmuschko:gradle-docker-plugin:3.2.0')
//for tests
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0'
}
}
allprojects {
repositories {
mavenCentral()
jcenter()
//spring dev
maven { url 'https://repo.spring.io/snapshot' }
maven { url 'https://repo.spring.io/milestone' }
}
}
subprojects {
repositories {
maven { url 'http://dl.bintray.com/kotlin/kotlin-eap-1.2' }
// for tests
maven { url "http://dl.bintray.com/jetbrains/spek" }
}
// for kotlin
apply plugin: 'kotlin'
// for tests
apply plugin: 'org.junit.platform.gradle.plugin'
apply plugin: 'kotlin-spring'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
// for tests
junitPlatform {
filters {
engines {
include 'spek'
}
}
}
sourceCompatibility = 1.9
dependencies {
// kotlin
compile("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
compile("org.jetbrains.kotlin:kotlin-test:${kotlinVersion}")
compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
// jackson
compile "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}"
compile "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}"
compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:${jacksonVersion}"
compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:${jacksonVersion}"
compile "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.2"
// Java WS RS
compile "javax.ws.rs:javax.ws.rs-api:${javaxWsRsVersion}"
// for tests
testCompile "org.jetbrains.spek:spek-api:${spekVersion}"
testRuntime "org.jetbrains.spek:spek-junit-platform-engine:${spekVersion}"
testCompile ("org.jetbrains.spek:spek-api:${spekVersion}") {
exclude group: 'org.jetbrains.kotlin'
}
testRuntime ("org.jetbrains.spek:spek-junit-platform-engine:${spekVersion}") {
exclude group: 'org.junit.platform'
exclude group: 'org.jetbrains.kotlin'
}
// spring security
compile('org.springframework.boot:spring-boot-starter-security')
testCompile('org.springframework.security:spring-security-test')
// begin: spring web without jackson
compile('org.springframework.boot:spring-boot-starter')
compile('org.springframework.boot:spring-boot-starter-tomcat')
compile('org.springframework:spring-web')
compile('org.springframework:spring-webmvc')
testCompile('org.springframework.boot:spring-boot-starter-test')
// end: spring web without jackson
// Keycloak
compile("org.keycloak:keycloak-spring-security-adapter:${keycloakVersion}")
compile("org.keycloak:keycloak-spring-boot-adapter:${keycloakVersion}")
compile("org.keycloak:keycloak-tomcat8-adapter:${keycloakVersion}")
compile("org.keycloak:keycloak-admin-client:${keycloakVersion}")
compile("org.jboss.resteasy:resteasy-client:${restEasyClientVersion}")
compile("org.jboss.resteasy:resteasy-jackson2-provider:${restEasyClientVersion}")
}
compileKotlin {
kotlinOptions.jvmTarget = '1.8'
kotlinOptions.allWarningsAsErrors = true
}
compileTestKotlin {
kotlinOptions.jvmTarget = '1.8'
}
}
The problem was the underlying class loader of ForkJoinPool.commonPool which is used by CompletableFuture.supplyAsync.
Because the problem and the solution is complex please refer to my other question for better understanding.
This question is only kept alive for this cross reference (and may hopefully lead others to the correct solution).

GORM not bootstrapping from JAR

Replacing a persistence layer in legacy app with a JAR file using Spring, Hibernate and GORM. Methods like person.save() work fine when running agains project with Gradle etc. in project. However, after I build the fat jar and reference it with -cp my-big-fat-gorm.jar I get:
java.lang.IllegalStateException: Method on class [blah.Person] was
used outside of a Grails application. If running in the context of a
test using the mocking API or bootstrap Grails correctly.
Using Spring boot for Spring, Hibernate4 and GORM and build.gradle file show below...
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'application'
mainClassName = "blah.App"
jar {
baseName = 'blah-gorm'
version = '1.0-SNAPSHOT'
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
configurations.runtime.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.8.2'
compile 'org.grails:gorm-hibernate4-spring-boot:1.1.0.RELEASE'
compile 'org.slf4j:slf4j-simple:1.7.7'
runtime 'com.h2database:h2:1.4.181'
}
Am I missing something in the JAR file creation that causes Spring boot to honor #Entity etc.?
Here is a GitHub project that illustrates this and should allow you to execute and see the same stuff I'm seeing.
https://github.com/twcrone/spring-gorm-jar
You don't have the Spring Boot Gradle plugin installed so you're not actually creating a fat JAR you need to add the following to your build.gradle file:
apply plugin: 'spring-boot'
buildscript {
ext {
springBootVersion = '1.1.0.M2'
groovyVersion = '2.3.2'
}
repositories {
mavenCentral()
maven {
url 'http://repo.spring.io/milestone'
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
With this in place doing gradle assemble and then java -jar ... results in bootstrapping GORM correctly

Resources