Vaadin 8 - widgetset - spring-boot

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")

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"

Multi module gradle: how to run module A before compiling modules B in a multi module project

We have a multi-module project in gradle. We have a "data" module that needs to be compiled (simple java 11 app) then run.
When we run java -jar data.jar after compiling the data module source is generated into the "webapp" module. With this generated source code we are now able to build the webapp module.
I am new to Gradle and struggling to figure out how do achieve this properly. I am especially concerned if I do it wrong I will make build caching fail.
Note: I am using Kotlin with Gradle 7.5.
The answer appears to be to create a custom configuration which produces a different artifact than the default.
task(taskJarGenerated, Jar::class) {
group = groupJooq
dependsOn(taskCompileGeneratedSource)
inputs.dir("$projectDir/build/classes/java/main")
outputs.file("${projectDir}/build/libs/data-1.0.jar")
from("$projectDir/build/classes/java/main")
}
artifacts {
add("generatedDbDataJar", tasks[taskJarGenerated])
}
Then you can reference this custom configuration "generatedDbDataJar" in other projects like this:
dependencies {
implementation(project(":data","generatedDbDataJar"))
}

Git repository with Maven project as a Gradle source dependency

This article describes an interesting feature of Gradle 4.10+ called a source dependency:
https://blog.gradle.org/introducing-source-dependencies
It allows to use a Git (for example a GitHub) source code repository to build a dependency from it. However it seems like it supports only Gradle projects as source dependencies. Is it possible to use a Maven project as well and if it's possible, please show an example.
When I try to use this feature with Maven project Gradle tries to find the build.gradle file there anyway (I see it when run Gradle with the --info option) and fails with an error message like:
Git repository at https://github.com/something/something.git did not contain a project publishing the specified dependency.
The short answer
... is: "no".
Under the hood, source dependencies are composite builds. These needs to be Gradle projects as the external projects are sort of merged with the main project.
The long answer
... is: "yes but it is hard".
It is actually mentioned in the same blog post you linked to (emphasis mine):
Source dependencies make these use cases simpler to implement. Gradle takes care of automatically checking out the correct versions of dependencies, making sure the binaries are built when required. It does this everywhere that the build is run. The checked out project doesn’t even need to have an existing Gradle build. This example shows a Gradle build consuming two source dependencies that have no build system by injecting a Gradle build via plugins. The injected configuration could do anything a regular Gradle plugin can do, such as wrapping an existing CMake or Maven build.
Because it sounded like it wasn't the biggest thing in the world to create bridge between a Maven and a Gradle project in source dependencies, I gave it a shot. And I have it working except for transitive dependencies. You will basically need to do what is shown in the examples linked to above, but instead of building native libraries, you make a call-out to Maven (e.g. using a Maven plugin for Gradle).
However, the scripts I ended up with are complex enough that I would suggest you instead build the Maven project yourself, deploy it to a local Maven repository and then add that repository to the Gradle project.
<edit>
The loooooooong answer
Alright, so here is how to actually do it. The feature is poorly documented, and appears to be mostly targeted towards native projects (like C++ or Swift).
Root project setup
Take a normal Gradle project with the Java plugin applied. I did a "gradle init" in an empty folder. Assume that in this project, you are depending on a library called `` that you later want to include as a source dependency:
// [root]/build.gradle
dependencies {
implementation 'org.example:my-maven-project:1.1'
}
Note that the version number defined here must match a Git tag in the repository. This is the code revision that will be checkout out.
Then in the settings file, we define a source dependency mapping for it:
// [root]/settings.gradle
rootProject.name = 'my-project'
includeBuild('plugins') // [1]
sourceControl {
gitRepository("https://github.com/jitpack/maven-simple") { // [2]
producesModule("org.example:my-maven-project") // [3]
plugins {
id "external-maven-build" // [4]
}
}
}
[1]: This includes a Gradle project called plugins that will be explained later.
[2]: This is just an arbitrary Maven project that I found, which was relatively simple. Substitute with the actual repository you have.
[3]: This is the name of the Maven module (the same as in the dependency block) that we are defining a source build for
[4]: This defines a custom settings plugin called external-maven-build that is defined in the plugins project, which will be explained later.
Plugins project structure
Inside the root project, we define a new Gradle project. Again, you can use gradle init to initialize it as a Groovy (or whatever you like) project. Delete all generated sources and tests.
// [root]/plugins/settings.gradle
// Empty, but used to mark this as a stand-alone project (and not part of a multi-build)
// [root]/plugins/build.gradle
plugins {
id 'groovy'
id 'java-gradle-plugin' // [1]
}
repositories {
gradlePluginPortal() // [2]
}
dependencies {
implementation "gradle.plugin.com.github.dkorotych.gradle.maven.exec:gradle-maven-exec-plugin:2.2.1" // [3]
}
gradlePlugin {
plugins {
"external-maven-build" { // [4]
id = "external-maven-build"
implementationClass = "org.example.ExternalMavenBuilder"
}
}
}
[1]: In this project, we are defining a new Gradle plugin. This is a standard way to do that.
[2]: To invoke Maven, I am using another 3rd party plugin, so we need to add the Gradle plugin portal as a repository.
[3]: This is the plugin used to invoke Maven. I am not too familiar with it, and I don't know how production ready it is. One thing I noticed is that it does not model inputs and outputs, so there are no built-in support for up-to-date checking. But this can be added retrospectively.
[4]: This defines the custom plugin. Notice that it has the same ID as used in the settings file in the root project.
Plugin implementation class
Now comes the fun stuff. I chose to do it in Groovy, but it can be done in any supported JVM languages of cause.
The plugin structure is just like any other Gradle plugin. One thing to note is that it is a Settings plugin, whereas you normally do Project plugins. This is needed as it we are basically defining a Gradle project at run-time, which needs to be done as part of the initialization phase.
// [root]/plugins/src/main/groovy/org/example/ExternalMavenBuilder.groovy
package org.example
import com.github.dkorotych.gradle.maven.exec.MavenExec
import org.gradle.api.Plugin
import org.gradle.api.artifacts.ConfigurablePublishArtifact
import org.gradle.api.initialization.Settings
class ExternalMavenBuilder implements Plugin<Settings> {
void apply(Settings settings) {
settings.with {
rootProject.name = 'my-maven-project' // [1]
gradle.rootProject {
group = "org.example" //[2]
pluginManager.apply("base") // [3]
pluginManager.apply("com.github.dkorotych.gradle-maven-exec") // [4]
def mavenBuild = tasks.register("mavenBuild", MavenExec) {
goals('clean', 'package') // [5]
}
artifacts.add("default", file("$projectDir/target/maven-simple-0.2-SNAPSHOT.jar")) { ConfigurablePublishArtifact a ->
a.builtBy(mavenBuild) // [6]
}
}
}
}
}
[1]: Must match the Maven module name
[2]: Must match the Maven module group
[3]: Defines tasks like "build" and "clean"
[4]: The 3rd party plugin that makes it more easy to invoke Maven
[5]: For options, see https://github.com/dkorotych/gradle-maven-exec-plugin
[6]: Adds the Maven output as an artifact in the "default" configuration
Be aware that it does not model transitive dependencies, and it is never up-to-date due to missing inputs and outputs.
This is as far as I got with a few hours of playing around with it. I think it can be generalized into a generic plugin published to the Gradle portal. But I think I have too much on my plate as it is already. If anyone would like to continue on from here, you have my blessing :)

Apply plugin in precompile script with Gradle and Kotlin

I'm trying to apply precompile script gradle.kts file (gradle.kts script is put in buildSrc/main/java. everything work normally except that i can not add a plugin with version. for example my test.gradle.kts
plugins {
id("io.gitlab.arturbosch.detekt") version "1.1.1"
}
but always got the error
Invalid plugin request [id: 'io.gitlab.arturbosch.detekt', version: '1.1.1']. Plugin requests from precompiled scripts must not include a version number. Please remove the version from the offending request and make sure the module containing the requested plugin 'io.gitlab.arturbosch.detekt' is an implementation dependency of project ':buildSrc'.
And also I cannot the class to configure extension
For example, this normally configuration is not working
configure<DetektExtension>
How can we specify plugin version in precompile script? and how can we configure the plugin?
Without being able to see your build structure and file tree I can only answer based on how I'm understanding your question. Based on the error message you are receiving, you should be declaring the plugin dependency in the project level build.gradle.kts:
plugins {
id("io.gitlab.arturbosch.detekt") version "1.1.1"
}
Then in your buildSrc/build.gradle implement it like so:
plugins {
`io.gitlab.arturbosch.detekt`
}
Gradle has samples on GitHub, from which I drew this example, here:
https://github.com/gradle/kotlin-dsl-samples/tree/master/samples/multi-kotlin-project-with-buildSrc

Spring Tools Suite and Gradle - Setup to use correct resources from inside STS

I have a Spring Boot Gradle project setup in Spring Tools Suite (3.7.2 RELEASE) with the following source folders:
- src/integration-test/java
- src/integration-test/resources
- src/main/java
- src/main/resources
- src/test/java
- src/test/resources`
Whenever I run the application or unit tests from within STS, I see that STS is using the resources found under src/integration-test/resources.
I see a duplicate resource warning in STS for files which exist in all 3 resource source folders. For example, I have an application.properties in all 3 source folders and I see following:
The resource is a duplicate of src/integration-test/resources/application.properties and was not copied to the output folder
If I run the application as a JAR or unit tests/integration tests from the command line (via gradle build), everything seems to use the correct resources. This makes me believe it is a problem with how STS/Eclipse is handling gradle.
Does anybody know of how I can configure STS to use the correct resource source folders when using gradle?
I think my problem may be related to (or the same as?) Spring Boot incorrectly loads test configuration when running from eclipse+gradle, https://issuetracker.springsource.com/browse/STS-3882, https://issues.gradle.org/browse/GRADLE-1777
I also tried the solution found here, but that seems to only fix Maven builds:
Spring Tool Suite finds spring-boot integration test configuration and does not start main application
I think my problem may be related to...
Yes, it is related but in my opinion not the same. That problem is caused by the runtime classpath being incorrect. This problem is an error coming from the eclipse project builder so it is a compile-time issue.
The problems are closely related though. Depending on your point of view, you could say they are the same (incorrect mixing of test and compile-time classpaths).
Here, specifically, the problem is that the eclipse builder tries to copy all the resources it finds in source folders to the project's single output folder. Each source folder has a 'application.properties'. The builder warns that it could not copy some of them because one would overwrite the other.
I think there may be a solution for this problem. But it is a solution that really should come from Gradle + ( BuildShip | STS Gradle Tooling) than from you.
It is possible in Eclipse to configure each source-folder individually to target a specific outputfolder. Maven + M2E are doing this correcty, but Gradle + (BuildsShip | STS Gradle Tooling) combdos do not.
For example this is what maven puts into the eclipse .classpath file when it configures a test resources folder:
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
Notice how it explicitly sets the output folder for that entry (to something different from the project's default output folder).
You may be able to address the problem yourself by modifying the .classpath for a gradle project in a similar way. Either by doing it manually or from your build.gradle.
I'm not sure this is worth it however as you will then likely still get hit by the runtime classpath issue (since these folders will still be added to your runtime classpath, your runtime classpath will end-up with two appication.properties resources, one which will 'shadow' the other. See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=482315)
I would say, the right thing to do is add a comment to the issue I linked, and hope they fix it soon as there is only so much you can do yourself by hacking the build.gradle file to modify the .classpath (this can not solve the runtime classpath issue, but in order to solve the runtime classpath issue, they would have to configure source folders to target individual output folder similar to what m2e does).
I would add this as a comment to #Kris's answer but it's too long.
I have solved the runtime classpath issue by adding the code below to my build.gradle file. The code generates an Eclipse launch configuration for the Spring Boot application class and includes only the runtime classpath (i.e. no test JARs).
My project uses the Gradle 'eclipse' plugin to generate the Eclipse project files (which I then import into Eclipse). Running the eclipseClasspath Gradle target will generate the launch file in the project's root directory.
def mainClassName = "com.example.MyApplication"
task eclipseApplicationLaunch {
group "IDE"
description "Generate an Eclipse launch configuration file for the Spring Boot application class"
}
eclipseApplicationLaunch << {
def writer = new FileWriter("${mainClassName.substring(mainClassName.lastIndexOf(".")+1)}.launch")
def xml = new groovy.xml.MarkupBuilder(writer)
xml.doubleQuotes = true
xml.launchConfiguration(type: "org.eclipse.jdt.launching.localJavaApplication") {
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_PATHS") {
listEntry(value:"/${project.name}/src/main/java/${mainClassName.replace(".","/")}.java")
}
listAttribute(key:"org.eclipse.debug.core.MAPPED_RESOURCE_TYPES") {
listEntry(value:"1")
}
listAttribute(key:"org.eclipse.jdt.launching.CLASSPATH") {
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry containerPath=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/\" javaProject=\"${project.name}\" path=\"1\" type=\"4\"/>\r\n")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry path=\"3\" projectName=\"${project.name}\" type=\"1\"/>\r\n")
configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def filePath = artifact.file.canonicalPath.replace("\\","/")
listEntry(value:"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n<runtimeClasspathEntry externalArchive=\"${filePath}\" path=\"3\" type=\"2\"/>\r\n")
}
}
booleanAttribute(key:"org.eclipse.jdt.launching.DEFAULT_CLASSPATH", value:"false")
stringAttribute(key:"org.eclipse.jdt.launching.MAIN_TYPE", value:"${mainClassName}")
stringAttribute(key:"org.eclipse.jdt.launching.PROGRAM_ARGUMENTS", value:"--spring.profiles.active=local --spring.config.location=conf/")
stringAttribute(key:"org.eclipse.jdt.launching.PROJECT_ATTR", value:"${project.name}")
stringAttribute(key:"org.eclipse.jdt.launching.VM_ARGUMENTS", value:"-Djava.net.preferIPv4Stack=true")
}
writer.close()
}
eclipseClasspath.dependsOn eclipseApplicationLaunch
I haven't modified the Eclipse .classpath file as per Kris' suggestion. Instead, I have added #Profile("test") to my test application class and #ActiveProfiles("test") to my test classes.

Resources