Making your Vaadin Add-on cope with dependency management systems

Matti Tahvonen
Matti says about web apps…
7 min readFeb 3, 2016

It is year 2016. Everybody expects Vaadin add-ons, and any other Java library, can be used by simply adding its dependency to the projects build file (Maven, IVY, Gradle) that is using it. Vaadin Directory provides these “maven coordinates” is the primary download option, even for libraries that are not built with Maven. But this has one limitation: if the library itself depends on another library the end users hast to manually provide external dependencies.

We recently run an automated tests against all our add-ons in the Directory, mostly to see if there was something that we broke in 7.6 series. To our surprise, the minor API changes broke only a couple of add-ons, but we found a number of add-ons that we just couldn’t test automatically with our Maven based tool — due to missing pom.xml.

pom.xml, the Maven format has become kind of de-facto dependency manifest that a library should provide — all other build systems can interpret its rules. This is why I suggest all add-on authors, whose add-on depends on another library, to provide at least pom.xml in their jar files. Here are two easy ways accomplish this.

Sidenote about multimodule projects:

Even if your add-on is already built with Maven there is a change that it doesn’t work via the Directory. There is currently a limitation that multimodule projects are not supported. Practically this means that your add-on module cannot have <parent> declaration. You can typically overcome this quite easily, but you’ll just need to replicate some common settings from your parent project to the level of the add-on module. Sorry about this inconvenience.

Quick and dirty — provide a manually tailored pom.xml

Vaadin Directory looks up for pom.xml from the jar file. Maven builds automatically place it there, but if you are creating the jar file e.g. directly form Eclispe or generating it with a plain old ant file, you could just place a manually crafted pom.xml insided your jar file.

As an example I’ll use a Sparklines add-on. The first step is to pick its “maven coordinates”, groupId, artifactId and version. You can find the values that were generated by the Vaadin Directory, from Vaadin Directory:

In this case the values where:

<groupId>org.vaadin.addons</groupId> 
<artifactId>sparklines</artifactId>
<version>7.0.2</version>

The pom.xml should now be created to META-INF/maven/GROUPID/ARTIFACTID, in this case META-INF/maven/org.vaadin.addons/sparklines. Initially give it the following content, note the groupId, artifactId and version that we stole from the Directory:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.vaadin.addons</groupId>
<artifactId>sparklines</artifactId>
<version>7.0.2</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
</dependencies>
</project>

You might also already update the version in pom.xml and do that always when exporting new releases to Directory.

Now to the real part, declaring the dependencies. In case of Sparklines, it only depepends on a one GWT module, GWT Graphics. You can find its maven coordinates from the Directory, but the awesome search feature in vaadin.com/maven may become handy when hunting down gwt coordinates for your add-ons dependencies. Add all dependencies to the pom.xml:s element. In Sparklines case that would be:

<dependencies>
<dependency>
<groupId>org.vaadin.addons</groupId>
<artifactId>gwt-graphics</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>

All done. Export a new version of your add-on and check from the generated jar file that the your pom.xml was correctly placed inside it. Your add-on users now can enjoy of fluent transitive dependency resolution.

Adding Maven build to your add-on project

A much better thing to do is to convert your project into Maven project. This way your add-on is actually much easier for other also to check out and develop, so expect to get more contributions as well.

One way is to use the vaadin-archetype-widget and just move your existing sources to the widget module and tests/demos to the demo module. I’m not a big fan of that archetype so I’ll present a better Maven setup for your add-ons, a similar what we have used for Vaadin TouchKit, Vaadin Charts and most of my personal add-on projects. In this setup you’ll just have one Maven module that generates your add-on jar file. The tests and examples are in the same project’s src/test/java and executed using an embedded jetty server.

Start by creating a following pom.xml to your projects root (note the maven coordinates and dependencies, stolen from the Directory like in previous step):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.vaadin.addons</groupId>
<artifactId>sparklines</artifactId>
<version>7.0.3-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>vaadin-addons</id>
<url>http://maven.vaadin.com/vaadin-addons</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.vaadin.addons</groupId>
<artifactId>gwt-graphics</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>

I also changed version to be the next development version, with -SNAPSHOT qualifier. This helps later to use Maven release plugin.

Next move old Java sources to Maven’s a standard location src/main/java, I did this with following commands, but feel free to use your OS GUI as well:

mkdir -p src/main/java 
mv src/* src/main/java/

Also prepare a test directory:

mkdir -p src/test/java

If your add-ons VAADIN directory contains stuff you wish to include in the add-on, move that to src/main/resources, which is reserved in Maven for all non Java stuff that should end up in the jar file:

mkdir -p src/main/resources 
mv WebContent/VAADIN src/main/resources/

As I want to follow good conventions I also move non java files from src/main/java to the resources directory.

mkdir -p src/main/resources/org/vaadin/sparklines 
mv src/main/java/org/vaadin/sparklines/public src/main/resources/org/vaadin/sparklines/
mv src/main/java/org/vaadin/sparklines/SparklinesWidgetset.gwt.xml src/main/resources/org/vaadin/sparklines/

At this point I moved to use my favourite IDE, NetBeans, but you can also complete this without IDE as well. If you haven’t used Maven built projects before, read this Maven tutorial. Also if there are some Eclipse specific configurations, it is better to delete that stuff before importing your project.

There is a big change that your project still don’t compile at this point, let’s add following dependencies to pom.xml to make it compile:

<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-server</artifactId>
<version>${vaadin.version}</version>
</dependency>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-client</artifactId>
<version>${vaadin.version}</version>
<scope>provided</scope>
</dependency>

Also add following property for Vaadin version to element:

<vaadin.version>7.6.1</vaadin.version>

Lets prepare the project for development and clean up the test classes from the jar file. During development and development we’ll need GWT compilation as Sparklines contains client side additions. This is done with following addition to your pom.xml’s element:

<build>
<plugins>
<plugin>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-maven-plugin</artifactId>
<version>${vaadin.version}</version>
<configuration>
<webappDirectory>${project.build.directory}/testwebapp/VAADIN/widgetsets</webappDirectory>
<extraJvmArgs>-Xmx1024M -Xss512m -XX:MaxPermSize=1024m</extraJvmArgs>
<hostedWebapp>${project.build.directory}/testwebapp</hostedWebapp>
<noServer>true</noServer>
<runTarget>http://localhost:9998/</runTarget>
<draftCompile>true</draftCompile>
<style>PRETTY</style>
<!-- If you do lots of e.g. plain css changes and don't wish to use
hosted mode, you can force compile easily with uncommenting following rule -->
<!-- <force>true</force> -->
<strict>true</strict>
</configuration>
<executions>
<execution>
<configuration>
</configuration>
<goals>
<goal>resources</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins>
</build>

Note that the purpose of this is just to compile the widgestset for our tests and the generated JS stuff does not end up in the generated jar file. Now lets set-up an embedded server that serves UI’s form the test directory. We’ll use a library called Addon Test Helpers. Add following dependency, note the test scope:

<dependency>
<groupId>org.vaadin</groupId>
<artifactId>addon-test-helpers</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>

The add-on contains cool helpers for add-on development, but an minimum we need a server launcher. Add following class to your project:

package com.example.sparklines;

import com.vaadin.annotations.Widgetset;
import org.vaadin.addonhelpers.TServer;

@Widgetset("org.vaadin.sparklines.SparklinesWidgetset")
public class UiRunner extends TServer {

/**
* Starts and embedded server for the tests
*/
public static void main(String[] args) throws Exception {
new UiRunner().startServer();
}
}

You’ll start the server (on port 9998 by default) by just executing the main method from this class.

In Sparklines, the test and demo class was called SparklinesRoot. I first moved that packege to src/test/java. Next I changed the super class to to org.vaadin.addonhelpers.AbstractTest and return your test component in the abstract getTestComponent method instead calling setContent in the init method.

Now can build the project and launch the development server (UIRunner class). If you open your browser to http://localhost:9998/ you’ll see a listing of test cases and examples you have in you project, together with a handy search funtionality. Clicking on test case opens it in a new browser window. You can have any number of tests you want.

Before making releases to Vaadin Directory, we’ll need to add couple of special headers to the generated jar file. Add following configuration for the jar plugin:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Vaadin-Package-Version>1</Vaadin-Package-Version>
<Vaadin-Widgetsets>org.vaadin.sparklines.SparklinesWidgetset</Vaadin-Widgetsets>
</manifestEntries>
</archive>
</configuration>
</plugin>

Note that the Widgetset manifest entry must much your project’s widgetset. Leave it empty if you project has no widgetset(s).

Now issue mvn install and you’ll produce your Directory compatible jar file.

You can still enhance the project by making it generate a zip file (with source jar). I also suggest to add notes to README file how to launch the test server and learn how to use Maven release plugin if you plan to do more that couple of releases for your add-on. See pointers for these setups from for example Viritin project.

--

--