Getting Started with Eclipse MicroProfile, Part 7: Helidon
Sunday, October 21, 2018 |Up next in our series comes an offering from, to me, a somewhat surprising source, Oracle, and that offering is Helidon. I first heard about in September 2018, and while it’s still pre-1.0, it looks extremely promising.
Like Hammock, Helidon projects are jar
projects, so we need to set the package type appropriately, then import
the Helidon dependencies:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<packaging>jar</packaging>
<properties>
<helidon.version>0.10.1</helidon.version>
<package>com.steeplesoft.microprofile.helidon</package>
<mainClass>${package}.Main</mainClass>
<libs.classpath.prefix>libs</libs.classpath.prefix>
<copied.libs.dir>${project.build.directory}/${libs.classpath.prefix}</copied.libs.dir>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.helidon</groupId>
<artifactId>helidon-bom</artifactId>
<version>${helidon.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Our dependencies, then are very short:
1
2
3
4
5
6
7
8
9
10
11
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.microprofile.bundles</groupId>
<artifactId>helidon-microprofile-1.2</artifactId>
</dependency>
</dependencies>
There are a number of dependencies pulled in transitively, but that’s fine. We only have to manage the one. Unless I’ve missed something, you do need to code an entry point. It’s an extremely small class that doesn’t do anything special, so I hope I’ve either overlooked something, or it’s something that will be fixed as the project matures. At any rate, here it is:
1
2
3
4
5
public final class Main {
public static void main(final String[] args) throws IOException {
Server.create().start();
}
}
It seems like a waste of time, but, as best as I can tell, it’s required at the moment. :) With that in place, we’re
almost ready to run it. We can, of course, run directly from the IDE, but to run from the command line, we need a
Maven plugin. Or two. The official docs show the maven-jar-plugin
, but I’ve also thrown in the maven-capsule-plugin
we saw from Hammock:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${copied.libs.dir}</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
<excludeScope>test</excludeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>${libs.classpath.prefix}</classpathPrefix>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>com.github.chrisdchristo</groupId>
<artifactId>capsule-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build</goal>
</goals>
<configuration>
<appClass>${mainClass}</appClass>
<type>fat</type>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The maven-dependency-plugin
copies all of the projects runtime dependencies to the configured directory, and the
maven-jar-plugin
builds a jar, specifying where to find the dependencies (in the lib
directory next to the jar) and
the main class to run. Using this plugin, we would run the project like this:
1
$ java -jar target/helidon-1.0-SNAPSHOT.jar
The libs
directory MUST be in target
or you will get a java.lang.NoClassDefFoundError
and the project will fail
to start. If you move the jar, you must move lib
as well.
With the maven-capsule-plugin
, it’s all self-contained:
1
$ java -jar target/helidon-1.0-SNAPSHOT-capsule.jar`
If you move the jar, like, say, when you deploy your application, all you need is the jar. I like this approach better, and many thanks to John Ament for introducing me to the plugin. :)
Testing, like Hammock, is also a bit different. There doesn’t appear to be Arquillian support for Helidon (yet?), so we test much like we did Hammock:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class HelidonTest {
private static Server server;
@BeforeClass
public static void setup() {
server = Server.create();
server.start();
}
@AfterClass
public static void shutdown() {
if (server != null) {
server.stop();
}
}
@Test
public void shouldSayWorld() throws URISyntaxException, IOException {
requestAndTest(new URI("http://localhost:8080"), "Hello, world");
}
@Test
public void shouldSayHelidon() throws URISyntaxException, IOException {
requestAndTest(new URIBuilder(new URI("http://localhost:8080"))
.setParameter("name", "Helidon")
.build(),
"Hello, Helidon");
}
private void requestAndTest(URI uri, String s) throws IOException {
try (CloseableHttpResponse response = HttpClients.createMinimal().execute(new HttpGet(uri))) {
Assertions.assertThat(EntityUtils.toString(response.getEntity()))
.isEqualTo(s);
}
}
}
And Bob’s your uncle! For more information, head over to the Helidon site for their getting started docs, which seem quite thorough and complete for such a young project.
In our next installment, we’ll wrap up our discussion with some closing thoughts.