Spring Gradle task for queryDsl fails after OpenApiGenerate - spring

Spring project using Gradle. I'm using OpenApiGenerate in combination with QueryDsl (to use with Spring MongoDB).
gradle clean build fails sometimes locally and always on Gitlab-CI:
Successfully generated code to task ':backend:openApiGenerate' property 'outputDir'
34 errors
> Task :backend:querydsl FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':backend:querydsl'.
QueryDsl fails because it can't find sources generated by OpenApiGenerate:
public class SomethingController implements SomethingApi {
^
Here's the gradle build file:
// QueryDSL
configurations {
querydslapt.extendsFrom compileClasspath
}
dependencies {
querydslapt 'com.querydsl:querydsl-apt:4.3.1'
}
task querydsl(type: JavaCompile, group: 'build', description: 'Generate the QueryDSL query types') {
source = sourceSets.main.java
classpath = configurations.compile + configurations.querydslapt
options.annotationProcessorPath = configurations.compile + configurations.querydslapt
options.compilerArgs = [
'-proc:only', //only annotations
'-processor', 'org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor'
]
destinationDir = file("${buildDir}/generated/src/main/java")
}
compileJava.dependsOn querydsl
// OpenAPI
openApiValidate {
inputSpec = "${rootDir}/openapi/specifications/schema.yaml".toString()
}
openApiGenerate {
generatorName = "spring"
library = "spring-boot"
inputSpec = "${rootDir}/openapi/specifications/schema.yaml".toString()
outputDir = "${buildDir}/generated".toString()
systemProperties = [
modelDocs : "false",
models : "",
apis : "",
supportingFiles: "false"
]
configOptions = [
useOptional : "true",
swaggerDocketConfig : "false",
performBeanValidation: "false",
useBeanValidation : "false",
useTags : "true",
singleContentTypes : "true",
basePackage : "...api",
configPackage : "...api",
title : rootProject.name,
java8 : "false",
dateLibrary : "java8",
serializableModel : "true",
artifactId : rootProject.name,
apiPackage : "...api",
modelPackage : "...model",
invokerPackage : "...api",
interfaceOnly : "true"
]
}
compileJava.dependsOn 'openApiGenerate'
Further changes that did not help:
Removed
compileJava.dependsOn 'openApiGenerate'
compileJava.dependsOn querydsl
and added
compileJava.dependsOn querydsl
querydsl.mustRunAfter 'openApiGenerate'
Does anyone have an idea? specifically on why does this sometimes work locally and sometimes not?

Is the output dir of openApiGenerate task is added somehow to src dir? If not, you should have
sourceSets{
main{
java{
dir openApiGenerate.outputDir
}}
}

What helped was changing destinationDir of querydsl to something else:
destinationDir = file("${buildDir}/generated/src/main/java")
to
destinationDir = file("${buildDir}/generated/src/main/java/querydsl")
=> There seems to have been a locking state enforced by openApiGenerate on the initial destinationDir since it was shared by both tasks.

Related

Gradle - two plugins have the same root block name, which resolve conflict

I'm trying to use 2 different plugins that have the same root block name, what's causing conflict and error in the build process.
The 2 plugins are defined in the build.gradle :
plugins {
id 'java'
id 'application'
id 'com.benjaminsproule.swagger' version '1.0.8'
id 'org.detoeuf.swagger-codegen' version '1.7.4'
}
apply plugin: 'org.detoeuf.swagger-codegen'
version '1.0-SNAPSHOT'
mainClassName = 'ServiceMain'
swagger {
apiSource {
springmvc = true
locations = ['com.google.charger']
schemes = ['https']
info {
title = 'Swagger Gradle Plugin Sample'
version = 'v1'
}
swaggerDirectory = 'swagger'
swaggerFileName = 'charger-service-api-swagger'
attachSwaggerArtifact = true
}
}
swagger {
inputSpec = "${project.projectDir}/swagger/charger-service-api-swagger.json"
outputDir = file("${project.projectDir}/../charger-server-api-client/")
lang = 'java'
additionalProperties = [
'invokerPackage' : 'com.google.ev.charger.server',
'modelPackage' : 'com.google.ev.charger.server.model',
'apiPackage' : 'com.google.ev.charger.server.api',
'dateLibrary' : 'joda',
'groupId' : 'com.google.ev',
'artifactId' : 'charger.server',
'artifactVersion' : '1.0.0',
'hideGenerationTimestamp': 'true'
]
}
sourceSets {
swagger {
java {
srcDir file("${project.buildDir.path}/swagger/src/main/java")
}
}
}
As you can see both plugins starts with the same block name (swagger),
Is there any way to specify the plugin for each configuration?
I ended up using code to resolve this issue,
I am using a property called "CreateSwagger" that I'm passing (either from CLI or from gradle.properties file) to separate the 2 scenarios.
The issue I had is that the plugins {} block is not allowed inside the if that evaluates the condition so I needed to use the "old" legacy plugin " apply plugin:"
This is how my build.gradle ended up looking:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "com.benjaminsproule:swagger-gradle-plugin:1.0.8"
classpath "gradle.plugin.org.detoeuf:swagger-codegen-plugin:1.7.4"
}
}
plugins {
id 'java'
id 'application'
id 'maven'
}
if(project.properties.containsKey('CreateSwagger')){
apply plugin: "com.benjaminsproule.swagger"
} else {
apply plugin: 'org.detoeuf.swagger-codegen'
}
version '1.0-SNAPSHOT'
mainClassName = 'EVChargerRestServiceMain'
if(project.properties.containsKey('CreateSwagger')){
swagger {
apiSource {
springmvc = true
locations = ['com.google.charger']
schemes = ['https']
info {
title = 'Swagger Gradle Plugin Sample'
version = 'v1'
}
swaggerDirectory = 'swagger'
swaggerFileName = 'charger-service-api-swagger'
attachSwaggerArtifact = true
}
}
}
else {
swagger {
inputSpec = "${project.projectDir}/swagger/charger-service-api-swagger.json"
outputDir = file("${project.projectDir}/../charger-server-api-client/")
lang = 'java'
additionalProperties = [
'invokerPackage' : 'com.google.ev.charger.server',
'modelPackage' : 'com.google.ev.charger.server.model',
'apiPackage' : 'com.google.ev.charger.server.api',
'dateLibrary' : 'joda',
'groupId' : 'com.google.ev',
'artifactId' : 'charger.server',
'artifactVersion' : '1.0.0',
'hideGenerationTimestamp': 'true'
]
}
}

Gradle startScript - Could not find or load main class

After looking into various answers in SO regarding the topic (which did not help me), I am raising a new question
I am new to Gradle, using version 1.0
Working with application plugin
it looks pretty simple
but I am facing difficulty running the start script
when I run the start script for windows, it says "Error: Cannot load or find main class"
Whereas with gradle run it runs successfully
here is my gradle file:
build.gradle
apply plugin: 'java'
apply plugin: 'application'
def properties = new Properties()
file('build.properties').withReader { properties.load(it) }
properties.each { key, value -> project.ext.set(key, value) }
task wrapper(type: Wrapper) {
gradleVersion = '1.0'
}
mainClassName = 'org.sample.Main'
defaultTasks 'clean', 'build'
repositories {
....
}
jar {
manifest {
def manifestClasspath = configurations.runtime.collect {
it.getName() }\
.join(' ')
attributes(
'Manifest-Version' : 1.0,
'Specification-Title' : project.ext.specTitle,
'Sepcification-Version' : project.ext.specVersion,
'Specification-Vendor' : project.ext.specVendor,
'Implementation-Title' : project.ext.implTitle,
'Implementation-Version': project.ext.implVersion,
'Implementation-Vendor' : project.ext.specVendor,
'Main-Class' : 'org.sample.Main',
'Class-Path' : manifestClasspath
)
}
}

Spring Boot 2 - Change Jar Name

I am using Spring Boot 2 in my Gradle project to do a build to jar in Jenkins, and I would like to change the name of that jar file.
By default, Spring Boot 2 used the Gradle property rootProject.name, which can be set in the /settings.gradle file.
However, I would like to change the jar file name, without changing the rootProject.name.
Here are my bootJar and springBoot sections of the build.gradle file:
bootJar {
launchScript()
}
.
springBoot {
buildInfo {
properties {
artifact = "jarName"
group = "groupName"
name = "projectName"
version = "1.0"
}
}
}
Note: artifact is not setting the jar name, as I expected it to, after reading: https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#integrating-with-actuator
archiveFileName is the new hotness. Everything else is deprecated.
bootJar {
archiveFileName = "${archiveBaseName.get()}.${archiveExtension.get()}"
}
or the Kotlin DSL equivalent:
tasks.getByName<org.springframework.boot.gradle.tasks.bundling.BootJar>("bootJar") {
this.archiveFileName.set("${archiveBaseName.get()}.${archiveExtension.get()}")
}
See:
https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html#org.gradle.api.tasks.bundling.Jar:archiveName
https://docs.gradle.org/current/userguide/lazy_configuration.html
Since bootJar tasks extends Jar you can use archiveName to set name the directly:
bootJar {
archiveName = 'whatever'
}
Have a look here.
Thanks to #AndyWilkinson for the answer!
bootJar {
baseName "jarName"
launchScript()
}
.
springBoot {
buildInfo {
properties {
group = "groupName"
name = "projectName"
version = "1.0"
}
}
}
For Gradle 6
bootJar {
archiveBaseName = 'freeway-server'
archiveVersion = '1.0.0'
archiveFileName = 'freeway-server.jar'
}
For get:-
System.out.print(bootJar.getArchiveBaseName().get())
System.out.print(bootJar.getArchiveVersion().get())
System.out.print(bootJar.getArchiveFileName().get())
My goal was to remove version from the archive name. I did it this way:
bootJar {
archiveName = "$baseName.$extension"
}
Now Gradle generates "project-name.jar" instead of "project-name-1.0-SNAPSHOT.jar". This solution is general and doesn't hardcode any particular archive name.
You can also use:
tasks.bootJar {
archiveFileName.set("app.jar")
}
Or with the jar-plugin
tasks.jar {
archiveFileName.set("app.jar")
}
Most people simply want to not have the version in the jar name, not change the name completely.
tasks.withType<org.springframework.boot.gradle.tasks.bundling.BootJar> {
archiveVersion.set("")
}
will do it using Kotlin DSL. The final name is given by tasks.bootJar.get().archiveFileName.get().
For me worked
project(':org.awseome.subproject') {
jar() {
archiveFileName = 'nameOfJar.jar'
}
}
inside of main build.gradle. Used
Gradle 6.X
Spring Boot 2.X

gradle wsimport

I'm running wsimport from my commandline to generate java classes from WSDL as below.
wsimport -J-Djavax.xml.accessExternalDTD=all
-J-D-Djavax.xml.accessExternalSchema=all
-b http://www.w3.org/2001/XMLSchema.xsd
-b customization.xjb
-s genSrc https://example.com/XYZ.asmx?wsdl
I want to create the equivalent gradle task.
I shouldn't be using any random custom gradle plugins due to company restrictions.
What's the best way to go about it?
As #lunicon mention, you should use an ant task, here are some improvements since gradle has change a couple of properties.
configurations {
jaxws
}
dependencies {
jaxws 'com.sun.xml.ws:jaxws-tools:2.1.4'
}
task wsimport {
ext.destDir = file("${projectDir}/src/main/generated")
doLast {
ant {
sourceSets.main.output.classesDirs.inits()
destDir.mkdirs()
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(keep: true,
sourcedestdir: 'src/main/java',
package: "com.example.client.api",
wsdl: 'src/main/resources/api.wsdl') {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
compileJava {
dependsOn wsimport
source wsimport.destDir
}
Found on web use ant task
more detail on metro project site
configurations {
jaxws
}
dependencies {
jaxws 'com.sun.xml.ws:jaxws-tools:2.1.4'
}
task wsimport {
ext.destDir = file("${projectDir}/src/main/generated")
doLast {
ant {
sourceSets.main.output.classesDir.mkdirs()
destDir.mkdirs()
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(keep: true,
destdir: sourceSets.main.output.classesDir,
sourcedestdir: destDir,
extension: "true",
verbose: "false",
quiet: "false",
package: "com.example.client.api",
xnocompile: "true",
wsdl: 'src/main/resources/api.wsdl') {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
compileJava {
dependsOn wsimport
source wsimport.destDir
}
configurations {
jaxws
}
dependencies {
jaxws 'com.sun.xml.ws:jaxws-tools:2.1.4'
}
task wsimport {
ext.destDir = file("${projectDir}/src/main/generated")
doLast {
ant {
destDir.mkdirs()
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(keep: true,
destdir: sourceSets.main.output.classesDir,
sourcedestdir: destDir,
extension: "true",
verbose: "false",
quiet: "false",
package: "com.example.client.api",
xnocompile: "true",
wsdl: 'c:/projects/gluecode/src/main/resources/api.wsdl') {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
This example copied from another answer of this question but removed one line as "sourceSets.main.output.classesDir.mkdirs()" and added the absolute path of .wsdl
To run the task form gradle follow the below process.
Goto run configuration and create new configuration.
From the configuration select either Gradle Project or Gradle Task from the list side
task name should same as task <<Task_Name>> {} provided in the .gradle file.
From the run configuration run the task then check the console log. In the console log some of the dependencies downloaded from the gradle repository.
This is the equivalent in Kotlin DSL
dependencies {
jaxws("com.sun.xml.ws:jaxws-tools:2.3.5")
jaxws("jakarta.xml.ws:jakarta.xml.ws-api:2.3.3")
jaxws("jakarta.activation:jakarta.activation-api:2.1.0")
jaxws("jakarta.xml.bind:jakarta.xml.bind-api:2.3.3")
}
tasks.register("wsimport") {
val destDir by extra("${buildDir}/generated/main/java")
doLast {
ant.withGroovyBuilder {
mkdir(destDir)
"taskdef"(
"name" to "wsimport",
"classname" to "com.sun.tools.ws.ant.WsImport",
"classpath" to configurations["jaxws"].asPath
)
"wsimport"(
"keep" to true,
"sourcedestdir" to destDir,
"wsdl" to "${projectDir}/some-api.wsdl",
"verbose" to true
) {
"xjcarg"("value" to "-XautoNameResolution")
}
}
}
}
tasks.compileJava {
dependsOn(tasks["wsimport"])
val destDir: String by tasks["wsimport"].extra
source(destDir)
}

Using gradle with a local artifactory repository

I am new to gradle and artifactory both.
What I want to accomplish is to have separate projects with each project creating a jar file that will be used by other projects in the same application.
For example, I have a utility project that has, wait for it..., utility classes. I then have a services project with the, that's right, services. The services use the utilities to accomplish some of their work.
I've spent several hours and finally have the utility project committing to my artifactory repository using this script:
buildscript {
repositories {
mavenLocal()
ivy {
url 'http://picard:8080/artifactory/plugins-release'
}
jcenter()
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1"
}
}
apply plugin: 'java'
apply plugin: "com.jfrog.artifactory"
archivesBaseName = 'heavyweight-software-util'
repositories {
mavenCentral()
ivy {
url 'http://picard:8080/artifactory/plugins-release'
}
}
dependencies {
testCompile("junit:junit:4.11")
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
}
artifactory {
contextUrl = "http://picard:8080/artifactory" //The base Artifactory URL if not overridden by the publisher/resolver
publish {
repository {
repoKey = 'libs-release-local'
username = 'xxxx'
password = "xxxx"
maven = false
ivy {
ivyLayout = '[organization]/[module]/[revision]/[type]s/ivy-[revision].xml'
artifactLayout = '[organization]/[module]/[revision]/[type]s/[module](-[classifier])-[revision].[ext]'
mavenCompatible = false
}
}
}
resolve {
repository {
repoKey = 'libs-release'
username = 'xxxx'
password = "xxxx"
maven = false
ivy {
ivyLayout = '[organization]/[module]/[revision]/[type]s/ivy-[revision].xml'
artifactLayout = '[organization]/[module]/[revision]/[type]s/[module](-[classifier])-[revision].[ext]'
mavenCompatible = false
}
}
}
}
When I run this I get the following:
C:\Users\thom\git\utility\Utility>gradle artifactoryPublish
[buildinfo] Not using buildInfo properties file for this build.
:artifactoryPublish
Deploying build descriptor to: http://picard:8080/artifactory/api/build
Build successfully deployed. Browse it in Artifactory under http://picard:8080/a
rtifactory/webapp/builds/Utility/1436807848026/2015-07-13T13:17:27.704-0400/
BUILD SUCCESSFUL
Total time: 6.874 secs
Hurrah! Or, so I thought.
Because as soon as this wrapped up, I thought, "Now how do I get this file out." I looked at the links above and they're there, but I can't see how this is a jar file. I tried looking at libs-release-local in my tree browser, but it shows 0 artifacts.
Here's what I found under build info JSON under the build:
{
"version" : "1.0.1",
"name" : "Utility",
"number" : "1436807848026",
"type" : "GRADLE",
"buildAgent" : {
"name" : "Gradle",
"version" : "2.4"
},
"agent" : {
"name" : "Gradle",
"version" : "2.4"
},
"started" : "2015-07-13T13:17:27.704-0400",
"durationMillis" : 474,
"principal" : "thom",
"artifactoryPrincipal" : "admin",
"licenseControl" : {
"runChecks" : false,
"includePublishedArtifacts" : false,
"autoDiscover" : false,
"licenseViolationsRecipientsList" : "",
"scopesList" : ""
},
"buildRetention" : {
"count" : -1,
"deleteBuildArtifacts" : true,
"buildNumbersNotToBeDiscarded" : [ ]
},
"governance" : {
"blackDuckProperties" : {
"runChecks" : false,
"includePublishedArtifacts" : false,
"autoCreateMissingComponentRequests" : false,
"autoDiscardStaleComponentRequests" : false
}
}
}
I've googled and researched and can't seem to figure out how to make use of the jar file I have committed to my repository.
OK, after reading: https://docs.gradle.org/current/userguide/publishing_ivy.html and https://docs.gradle.org/current/userguide/artifact_management.html and finally, http://forums.jfrog.org/405-HTTP-method-PUT-not-supported-td5786632.html I have pieced together an answer to my question. I have attached the build script that performs the upload properly...
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath "org.jfrog.buildinfo:build-info-extractor-gradle:3.1.1"
}
}
apply plugin: 'java'
apply plugin: 'ivy-publish'
archivesBaseName = 'heavyweight-software-util'
repositories {
mavenCentral()
ivy {
url 'http://picard:8080/artifactory/plugins-release'
}
}
dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.+'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.+'
testCompile("junit:junit:4.11")
}
publishing {
publications {
ivy(IvyPublication) {
organisation 'com.heavyweightsoftware'
module 'heavyweight-util'
revision '1.0'
from components.java
}
}
repositories {
ivy {
url 'http://picard:8080/artifactory/libs-release-local'
credentials {
username "xxxxx"
password "xxxxx"
}
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.8'
}
Now that I know that the publication is working correctly, I should be able to use the repository without issue.

Resources