Openapi codegen by gradle plugin: UI not showing correctly - spring-boot

I'm trying to test openapi codegenerator via gradle plugin. So, I have .yml file with documentation (ran it in https://editor.swagger.io/ , looks cool)
openapi: 3.0.2
info:
title: Testing docs
version: 1.0.0
tags:
- name: Registration
paths:
/registration:
post:
tags:
- Registration
summary: Register user
...
Here's part of my build.gradle
plugins {
id "org.openapi.generator" version "5.0.1"
}
def sDir= "$buildDir/generated"
openApiGenerate {
generatorName = "spring"
inputSpec = "$rootDir/src/main/resources/documentation/openapi.yml"
outputDir = "${sDir}"
apiPackage = "generated.api"
invokerPackage = "generated.invoker"
modelPackage = "generated.model"
configOptions = [
interfaceOnly: "true",
useTags: "true"
]
}
...
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-ui:1.5.2'
implementation 'io.springfox:springfox-swagger2:3.0.0'
implementation 'org.openapitools:jackson-databind-nullable:0.2.1'
}
I've got bunch of generated interfaces annotated with #Tag and #Api, implemented some of them, but on /swagger-ui.html I do not see tags. Like, I'm getting "not implemented" status, when I run not implemented requests, but I do not see right ui - it looks autogenerated, like when you don't use any of swagger annotations on methods. I can only think that I messed up with some dependencies, but can't really get a clue.

The ui you see is not generated from the documentation .yml file you use to generate your code.
Instead, the ui is generated from the generated code, which has it's own annotations that currently are springfox annotations, which are swagger2 annotations instead of openapi 3 annotations (although your original file is openapi 3).
Generated openapi 3 annotations support is coming soon, but in any case, in short, you should have to complete missing annotations and necessary beans yourself, but this way makes it very hard to match the resulting openapi definition to your original documentation file.
Luckily there's a better alternative:
Just add your yml file in src/main/resources/static and add this line to your application.properties file:
springdoc.swagger-ui.url=/<your_file>.yml
As stated here https://springdoc.org/#how-can-use-custom-jsonyml-file-instead-of-generated-one.
You already have springdoc-ui dependency so you don't need to add any more dependencies.
This will ignore your code annotations and generate the ui directly from your documentation .yml file

Related

Gradle Idea plugin - issues with specifing test sources

I'm trying to create a custom source set and mark its contents in Intellij Idea as a Test Sources Root. I tried to use idea plugin and do it according to the gradle official website but it is not clear for me how it works.
First of all the documentation specifies the following configuration setup
idea {
module {
testSources.from(sourceSets["intTest"].java.srcDirs)
}
}
When I try to use it i receive Unresolved reference: testSources. Where is it coming from?
Then I tried to use:
idea {
module {
testSourceDirs = intTest.java.srcDirs
}
}
it works fine as long as I use only Java. After applying Kotlin plugin however, both kotlin and java + resources folder are again treated as Sources Root not Test Sources. To fix that I had to change from:
testSourceDirs = intTest.java.srcDirs
to:
testSourceDirs = intTest.kotlin.srcDirs
and now all folders are Test Source Root again. Since kotlin.srcDirs also includes java.srcDirs it looks like you have to specify all, otherwise it is ignored...
Now the real issue came when I used gradle-avro-plugin. Applying it made my folders marked as Sources Root again. I believe it is because it adds another avro directory, but just to main source set.
Does anyone know how to make it marked as Test Sources having both kotlin and avro plugin applied? Am I doing something wrong here? Beacause this beheviour seems to be buggy in the first place.
Tested with:
IntelliJ IDEA 2022.3.1 (Ultimate Edition)
Gradle 6.8.3 and 7.4.2
Plugin id("com.github.davidmc24.gradle.plugin.avro") version "1.5.0"
Plugin kotlin("jvm") version "1.7.0"

Custom configuration and resolving only compile dependencies

i'm currently writing a small plugin but i'm stuck when i want to get a list of all dependencies that are used.
what i'm doing
inside the plugin i create a new configuration
def config = project.configurations.create(sourceSet.getTaskName('foo', 'bar'))
in the build.gradle that uses the plugin i add some dependencies to this configuration
dependencies {
fooTestBar(project(':module'))
}
and in module/build.gradle i have
plugins {
id 'java-library'
}
dependencies {
implementation('org.apache.commons:commons-collections4:4.4')
api('org.springframework:spring-context:5.2.11.RELEASE')
}
when i now do the following in the plugin
List<ResolvedArtifact> = config.resolvedConfiguration.firstLevelModuleDependencies.allModuleArtifacts.flatten()
i get the artifacts from both declarations in :module, but what i'm interested in is only the api dependency, means the one that is also used when compiling the project
it looks like the entire configurations is treated as a runtime configuration, so i have all artifacts including the transitive ones from both declarations, instead of only the api one including the transitive ones from api
until now i was not able to find any way to see if a resolved dependency / artifact is of type api which i do not want to have in my result list
i had to add the attribute for the usage
config.attributes {
attribute( Usage.USAGE_ATTRIBUTE, objects.named( Usage, Usage.JAVA_API ) )
}
https://docs.gradle.org/current/userguide/variant_model.html
https://docs.gradle.org/current/userguide/variant_attributes.html
thanks Chris Doré on https://discuss.gradle.org/t/custom-configuration-and-resolving-only-compile-dependencies/38891

Grails 3 exclude class

I am developing a grails plugin and I would like to exclude a class at build time. Let's say I have a service under grails-app/services/MyService.groovy. I would like to build 2 versions of this plugin, one which contains MyService, one which doesn't. Is there a way to achieve this?
In your plugin descriptor you can define pluginExcludes to express items that you want excluded from the plugin. For example:
def pluginExcludes = [
'**/com/demo/**'
]
You can also exclude contents from the jar file:
// build.gradle
jar {
exclude "com/demo/**"
}
More info available at https://docs.grails.org/3.3.x/guide/plugins.html.

Configuring the Swagger codegen with Gradle. How does the provided Gradle script work?

I am doing battle with this code here: https://github.com/thebignet/swagger-codegen-gradle-plugin-example
Trying to build a REST client using Swagger codegen and Gradle. I am new to Gradle and looking at this example is quite confusing as there are multiple variables / properties / names that I have no clue where they come from or what they do. Especially this part:
clean.doFirst {
delete(swaggerOutputDir)
}
configurations {
swagger
}
sourceSets {
swagger {
compileClasspath = configurations.swaggerCompile
java {
srcDir file("${project.buildDir.path}/swagger/src/main/java")
}
}
main {
compileClasspath += swagger.output
runtimeClasspath += swagger.output
}
test {
compileClasspath += swagger.output
runtimeClasspath += swagger.output
}
}
compileSwaggerJava.dependsOn generateApi
classes.dependsOn swaggerClasses
compileJava.dependsOn compileSwaggerJava
swagger.output - where this comes from?
classes, compileJava, swaggerClasses, compileSwaggerJava
What are all of those? They don't seem to be defined anywhere and seem to be randomly named?
Then the readme says:
In order to generate Swagger source code, launch the following task.
generateApi : generate Swagger code
Where the hell are Swagger and code coming from?
Any clarifications are much appreciated and I believe will help a lot more people.
To fully understand this code, you have to read through the Gradle DSL (domain-specific-language)
A SourceSet:
A SourceSet represents a logical group of Java source and resources.
Inside the block sourceSets{ }, a new SourceSet swagger is defined.
In the above link to the SourceSet's definition, you will notice that since swagger is now a SourceSet, it has the property 'output' which provides all the output directories of this SourceSet: thus, you can call swagger.output
In every Gradle Java project, there is the assumption there are main sources and test sources. This assumption is introduced by the java plugin, which is required for Gradle to process Java. (This standardized layout stems from the Standard Directory Layout.) You configure those source sets through main{} and test{}. Of course, you may have more source sets.
What compileClasspath += swagger.output and runtimeClasspath += swagger.output does, is add the swagger-generated code (or any swagger output in general) in their compile-time and runtime classpath directory. Since swagger does code generation, this is expected behavior.
Now, about Gradle Tasks:
A Task represents a single atomic piece of work for a build, such as compiling classes or generating javadoc.
The java plugin mentioned above, when creating a new SourceSet, creates also some associated tasks: compileSourceSetJava, processSourceSetResources and sourceSetClasses (replacing SourceSet with each SourceSet's name). That's what those compileSwaggerJava, swaggerClasses are, the generated tasks from the swagger SourceSet.
For the standard sourcesets, those tasks are:
main sourceset's tasks: compileJava, processResources, classes
test sourceset's tasks: compileTestJava, processTestResources, testClasses
A task may have dependencies on other tasks or might be scheduled to always run after another task.
This is configured through the task's properties. One of those, is the dependsOn property which explains this last block of your provided code.
(Note: the generateApi task in the last block of code, is defined in the link the OP shared in the question)

Vaadin 8 - widgetset

I added Vaadin google maps addon to my Spring boot project. If I want to display map on site, then I get error:
Widgetset 'com.vaadin.DefaultWidgetSet' does not contain an
implementation for com.vaadin.tapio.googlemaps.GoogleMap. Check the
connector's #Connect mapping, the widgetset's GWT module description
file and re-compile your widgetset. In case you have downloaded a
vaadin add-on package, you might want to refer to add on instructions
If I add #Widgetset("com.vaadin.v7.Vaadin7WidgetSet") annotation to UI class, then I get this error:
Failed to load the widgetset:
./VAADIN/widgetsets/com.vaadin.v7.Vaadin7WidgetSet/com.vaadin.v7.Vaadin7WidgetSet.nocache.js?1521722356809
And I have a question: How should a widgetset look like, how to build it? I was looking for examples and tutorials but I still can't do this.
I read that in early Vaadin versions, I should do a manual compilation widget, but in version 8 compiling is automated.
Maybe this is important information, but I use gradle not maven.
Please help me, because I am trying to fix it for a week.
As soon as you include add-ons in your Vaadin project, you need to compile the widgetset and the widgetset needs to include the add-on widgetsets.
I have the following src/main/resources/widgetsets/AppWidgetset.gwt.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Vaadin//DTD Vaadin 7//EN" "https://raw.github.com/vaadin/gwt/master/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.vaadin.DefaultWidgetSet"/>
<!-- include widgetsets of external add-ons here -->
<inherits name="org.vaadin.hene.popupbutton.widgetset.PopupbuttonWidgetset"/>
</module>
This includes the Vaadin PopupButton add-on. Of course you need to adapt it to include your desired add-ons. My gradle build looks like:
configurations {
vaadinAddOns
widgetSetCompilation
themeCompilation
}
dependencies {
themeCompilation('com.vaadin:vaadin-spring-boot-starter')
}
task compileWidgetSet(type: JavaExec) {
// execution of Vaadin GWT compiler
classpath configurations.vaadinAddOns
classpath configurations.widgetSetCompilation
classpath file("${projectDir}/src/main/resources/widgetsets")
main = 'com.google.gwt.dev.Compiler'
args '-war', "${projectDir}/src/main/resources/VAADIN/widgetsets"
args '-strict'
args '-logLevel', 'WARN'
args 'AppWidgetset'
jvmArgs '-Xmx1024M'
doLast {
// clean up unnecessary stuff
file("${projectDir}/src/main/resources/VAADIN/gwt-unitCache").deleteDir()
file("${projectDir}/src/main/resources/VAADIN/widgetsets/WEB-INF").deleteDir()
}
// for the up-to-date check of gradle
outputs.dir("${projectDir}/src/main/resources/VAADIN/widgetsets/AppWidgetset")
}
clean.dependsOn cleanCompileWidgetSet
processResources.dependsOn compileWidgetSet
// on-the-fly theme compilation is disabled in Vaadin production mode, so we do the compilation ourselves
task compileThemes {
def themesFolder = file("${projectDir}/src/main/resources/VAADIN/themes")
new FileNameFinder().getFileNames(themesFolder.toString(), '**/styles.scss').each { path ->
def themeFolder = file(path).getParentFile()
def fileIn = new File(themeFolder, 'styles.scss')
def fileOut = new File("${buildDir}/resources/main/VAADIN/themes/${themeFolder.getName()}/styles.css")
dependsOn tasks.create("compileTheme${themeFolder.getName().capitalize()}", JavaExec) {
classpath configurations.themeCompilation
main = 'com.vaadin.sass.SassCompiler'
args fileIn, fileOut
inputs.dir(themesFolder)
outputs.file(fileOut)
}
}
}
processResources.dependsOn compileThemes
And finally the annotation:
#Widgetset("AppWidgetset")
public class MyUI extends UI {
...
}
This is a lot of manual stuff. You can omit the theme compilation if you do not run in Vaadin production mode for now. I am almost sure that there is a Vaadin gradle plugin out there that simplifies the widgetset and theme compilation but when I was looking for it it didn't match my requirements.
Btw: Vaadin 7 widgetset is not appropriate for Vaadin 8 :)
I sounds like your project is missing build setup for Vaadin extensions requiring client side extensions (aka custom widgetset). This happens often with new Spring users as start.spring.io don't currently support adding third party Maven plugins. Addin vaadin-maven-plugin and doing full build should fix the issue.
To see a Spring Boot project with vaadin-maven-plugin configured, I suggest to use the viritin-spring-archetype and see the generated project (and especially the pom.xml generated by the project). You can also manually copy the relevant parts from the official plain servlet project template (generated by the default archetype or IDE plugins).
When using Gradle the fix is similar in nature. If you created the project using start.spring.io, you can just add the gradle-vaadin-plugin to your project, by adding follow snippet to your build.gradle file, e.g. after buildScript section:
plugins {
id 'com.devsoap.plugin.vaadin' version '1.3.1'
}
You will also need to declare dependencies with client side extensions as follows (use google maps coordinates instead):
vaadinCompile("org.vaadin.addon:v-leaflet:2.0.6")

Resources