Saturday, February 08, 2020

Review of Java 13 "Preview Features" in Spring Boot app with Maven . . .

Writing code in Groovy for few years and now back to Java, I couldn't resist using one of the preview features added to Java 13 - Text Blocks. Multiline String literal is the most ugliest part of Java code polluted with escape characters and concatenation operator all over, to an extent that your brain cannot read the string actually. Writing a multiline XML/JSON string is a nightmare. There is no reason to live with such constraints in a language for this long. At last, Java 13 added support for multiline string as a preview feature. It's not going to go away but might go through some changes in future releases and is a pleasant to start using, infact. This blog post is not about text blocks, but several things that you need to do correctly in order to fully leverage preview features in a SpringBoot application with Maven as the build tool.

I was working on a Spring Boot micro-service app with Java 13 from ground up. I had to define a long String literal for a message. After enjoying Groovy's fantastic and superior support for defining multi-line text as a String for long enough, my eyes would certainly go blind if I do not leverage Java 13 Text Blocks in Java code for this. Thought it appears to be simple to just enable Java language preview feature with --enable-preview flag, in reality it goes beyond that simplicity. Not a surprise, after all technology only gets complex ;)

Environment: Java 13.01, Spring Boot 2.2.4.RELEASE, Maven 3.6.2, IntelliJ IDEA ULTIMATE 2019.3 on macOS High Sierra 10.13.6

Java 13 --enable-preview language flag

This is the flag you need to set for enabling Java 13 preview features, both for compiler (javac) and JVM launcher (java). Without this flag your code will not get compiled or run. With this flag you will still see a warning but can ignore safely. In order to use Java 13 features in a SpringBoot app with Maven, you need one or many or all of the following.

IntelliJ IDEA Setup

The moment I declared a String and assigned a multiline text literal, IntelliJ got unhappy. A warning bulb popped up and the message was: Text block literals are not supported at language level '13'. I did not understand what the message was saying but the link to Module settings took me to my API module level settings which was like:


It would have been much useful if the message was: Text block literals are not supported at language level '13 (No Preview)' and that current option chosen was: 13 (No Preview) language features. When I pulled down the option list, there I saw the 13 (Preview) option right below it:


That's IntelliJ way of setting the compiler flag --enable-preview to enable preview feature at the module level, if your are coding in a module in a multi-module maven project. Once I switched to the (Preview) one, IntelliJ was happy to compile my code.

NOTE: If you have a multi-module Maven project, you may need to set this Language level at the project level as well as at the each module level.

Maven Build Setup

IDE compiles code as we go on writing code and helps us with missing configurations and fixing errors. But the build system like Maven or Gradle is the one used at the end to clean, compile, package and run the app. Of course, maven build fails without additional setup for enabling preview features. The config setup needs the --enable-preview flag at few places depending on what plugins you have in it's pom.xml file. I had at least four places where I had to use this flag with some additional argument setup as well to get this feature fully enabled for my Spring Boot app.

1. Maven Compiler Plugin

Maven Compiler plugin compiles the project source code. You need to have an additional --enable-preview compiler argument in it's configuration to enable preview features as shown below:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <release>13</release> <compilerArgs> <arg>--enable-preview</arg> <arg>-Xlint:all</arg> </compilerArgs> </configuration> </plugin>

2. Maven Surefire Plugin

Surefire plugin is used during test phase to run unit tests. You need to have an additional --enable-preview compiler argument in it's configuration to enable preview features. In addition to this you also need to have ${argLine} without which you will not have code coverage reports generated if you are using code coverage libraries like JaCoCo. An example configuration setup is shown below:

<!-- surefire for unit tests --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <configuration> <argLine>${argLine} --enable-preview</argLine> </configuration> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.22.2</version> </dependency> </dependencies> </plugin>

3. Maven Failsafe Plugin

Failsafe plugin is used to during test phase to run integration tests. You need to have an additional --enable-preview compiler argument in it's configuration to enable preview features. In addition to this you also need to have ${argLine} without which you will not have code coverage reports generated if you are using code coverage libraries like JaCoCo. An example configuration  setup is shown below:

<!-- failsafe for integration tests --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>2.22.2</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> <configuration> <argLine>${argLine} --enable-preview</argLine> <additionalClasspathElements> <additionalClasspathElement>${basedir}/target/classes</additionalClasspathElement> </additionalClasspathElements> <includes> <include>**/*IT.java</include> </includes> </configuration> </plugin>

4. Springboot Maven Plugin

Springboot Maven plugin runs your application by launching the embedded Tomcat Server and JVM. You need to tell the JVM launcher to enable preview features by setting the flag as shown below:

<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring.boot.version}</version> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> <execution> <!-- Useful info on /actuator/info --> <id>build-info</id> <goals> <goal>build-info</goal> </goals> </execution> </executions> <configuration> <mainClass>com.giri.api.Application</mainClass> <jvmArguments>${argLine} --enable-preview</jvmArguments> </configuration> </plugin>


TIP

In IntelliJ IDEA, if you do not have the (Preview) language level set, and if you mouseover the multiline text the warning message shown up like below is bit misleading.


However, when you click on the multi-line literal text, the error shown as below is more meaningful:

References

No comments:

Post a Comment