Understanding Apache Maven – Part 1 – Basics

java, maven

Published: 2020-05 (May 2020)
Verified with: Apache Maven 3.6.3

Link to an index, to find other blogs in this series.

This blog (a part of the series) is an introduction to Apache Maven basics.

Apache Maven (commonly referred to as “maven” ) is a Build Management tool. Maven is primarily used to build Java projects. Other language projects can also be built using maven. Apache Maven is written in Java, for most part. It is an open source project.

Maven follows a convention-over-configuration philosophy. More on this follows.

Why is Maven a Build Management tool?

Maven aims at achieving the following for a project:

  • build tooling
  • version management
  • re-usability
  • maintainability
  • comprehensibility
  • inheritance

In addition, maven provides capabilities for a project to :

  • produce different build targets and results builds via profiles
  • test code
  • generate documentation
  • furnish metrics and reports
  • deploy built artifacts

What is Convention-Over-Configuration?

Convention-over-configuration is a software paradigm. The main intent of such a paradigm is to reduce the number of superfluous decisions required by a developer to build her/his project. The paradigm aims to meet and satisfy the “principle of least astonishment“.

Apache Maven – convention over configuration

Apache Maven provides sensible defaults for a project’s build management. A developer can then choose to override any preset defaults.

An example of such is clear in the conventional directory structure of a maven project.

project
|
|____src
|   |
|   |____main
|   |   |
|   |   |____java
|   |   |
|   |   |____resources
|   |
|   |____test
|       |
|       |____java
|       |
|       |____resources
| 
|____pom.xml

Printed using: alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"

In this directory structure, the source code is, by convention located under the project root directory in a src directory. Under the src directory there exists a main directory that is, by convention expected to contain production code, that is, code that is expected to be a part of the final executable. Parallel to the main directory, there is a test directory, where test code is expected, by convention. Java code, once again, by convention (I think by now the point is made, will stop referring to it) exists in a java directory either in the production or in the test location. Similarly resources needed for production or test outputs, reside respectively in the resources directory.

This is just one example. Maven uses the convention-over-configuration philosophy in many other areas.

What are some Maven capabilities?

A few features that maven offers (this is not a comprehensive list):

  • Validate the project structure
  • Auto generate any code/resources needed by the project
  • Generate any documentation
  • Compile source code, display errors / warnings
  • Test the project based on existing tests
  • Package compiled code into artifacts (examples include .jar, .war, .ear, .zip archives and many more)
  • Package source code into downloadable archives / artifacts
  • Install packaged artifacts on to a server for deployment or into a repository for distribution
  • Generate site reports and test evidence
  • Report a build as success or failure
  • . . .

How does Maven work?

Maven uses a Project Object Model (POM) to manage a project. Maven commands execute parts of its Project Object Model. A Project Object Model is usually described as an XML document. A POM description is NOT limited to XML. Other formats can be used to describe the Project Object Model, however, XML was the first format used.

A picture to illustrate a typical maven execution:

A pictorial overview of how maven interacts with a project's Project Object Model. Includes assembling, download of dependencies and plugins, execution of build lifecycles and an upload of build artifacts to either a local repository or to a maven repository on a network
Maven – A pictorial overview

The next blog in this series will dig into details of a Project Object Model (POM). Have fun !

             IndexPart 2
The Project Object Model (POM) and Effective POMs

Understanding Apache Maven – The Series

java, maven

This is a series of blogs about Apache Maven – a build management tool. This series is intended to be an introductory set of blogs to introduce, familiarize or brush up on maven.

The blogs in this series:

Part 1 – Apache Maven basics
Bare Link: https://cguntur.me/2020/05/23/understanding-apache-maven-part-1/

Part 2 – The Project Object Model (POM) and Effective POMs
Bare Link: https://cguntur.me/2020/05/24/understanding-apache-maven-part-2/

Part 3 – Dependency coordinates and POM hierarchies
Bare Link: https://cguntur.me/2020/05/26/understanding-apache-maven-part-3/

Part 4 – Maven Lifecycles, Phases, Plugins and Goals
Bare Link: https://cguntur.me/2020/05/29/understanding-apache-maven-part-4/

Part 5 – Dependencies in Maven
Bare Link: https://cguntur.me/2020/06/03/understanding-apache-maven-part-5/

Part 6 – Maven Project Object Model (POM) Reference
Bare Link: https://cguntur.me/2020/06/20/understanding-apache-maven-part-6/

Part 7 – Configuring Apache Maven
Bare Link: https://cguntur.me/2020/06/27/understanding-apache-maven-part-7/

Part 8 – Maven Plugins
Bare Link: https://cguntur.me/2020/07/04/understanding-apache-maven-part-8/

Part 9 – Versions in Maven
Bare Link: https://cguntur.me/2020/07/05/understanding-apache-maven-part-9/

Using JUnit5 – Part 4 – Filtering Tests

java, junit5

Published: 2019-07 (July 2019)
Relevant for: JUnit 5.5.0

JUnit5 Blog Series

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

In Part 1 of the blog series, we looked at several annotations used in JUnit5. We covered test methods as well as lifecycle methods.

In Part 2 of the blog series, we covered the basics of testing using JUnit5. We covered test annotations such as marking a test method and asserting. We saw how a test method could be tagged and how assumptions can be used. We finally wrapped up with test execution ordering mechanisms.

In Part 3 of the blog series, we detailed ways in which JUnit test classes and test methods could be customized with readable and meaningful names rather than the standard class and method names.

This post will cover filtering JUnit tests for execution. There are several reasons for running a subset of your comprehensive suite of tests. Some example usages include:

  • You may have unit and integration tests and wish to only run unit tests.
  • You may want a sanity check with the core features alone being tested.
  • You may wish to bypass a few tests to test a specific situation.
  • You may wish to skip a few failing tests, since you know they fail.

Filtration Types

Dynamic filtration

In Part 2 of the blog series, we covered what I term, dynamic filtration. This was done using Assumptions (https://junit.org/junit5/docs/5.5.0/user-guide/#writing-tests-assumptions). Assumptions are conditions that when not met, cause the test to be aborted rather than fail. Assumptions are a great feature to dynamically filter unit tests.

Assumptions are evaluated during execution of the test class, and are embedded within the code block of the test method. Repeating the example we covered in that blog:

class TestWithAssumptions {

    @Test
    void testOnlyOnHost123() {
        assumeTrue("host123".equals(System.getenv("HOSTNAME")));
        // remainder of test
    }

    @Test
    void testOnHost123OrAbortWithMessage() {
        assumeTrue("host123".equals(System.getenv("HOSTNAME")),
            () -> "Aborting test: not on host123");
        // remainder of test
    }

}

Static filtration

In Part 2 of the blog series, we covered the @Tag (https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/Tag.html) annotation on the unit test method. This annotation can be used to statically label classes and methods. The benefit of such an identification (or label or category) is that a predicate check can be made of such.

Filtering tests based on static labels is what I term static filtration. Since the Tag is an annotation, it is not a part of the code block that executes the unit test. A Tag is a @Repeatable (https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/annotation/Repeatable.html) annotation, which implies a class or method can have several tags annotating them.

How Static Filtration works

Code Katas are means to teach a concept, a feature or a functionality. In some Code Katas we deliberately remove logic to make tests fail. The mission for the student is to “fix” these tests. Since this is a learning process, there is a known solution also provided. In order to verify that the solutions are not failing, we can run a build that executes only the solutions (and other tests that are expected to pass). A way of doing that is to leverage Tags.

In this above example, we can thus tag known passing tests as “PASSING” and the kata tests as “TODO”.

See PublicMethodInvocationTest (https://github.com/c-guntur/java-katas/blob/baseline/java-handles/src/test/java/none/cvg/methods/PublicMethodInvocationTest.java).

  • On line 37, the test method is tagged as PASSING. This is a test that is expected to always pass, since it is already solved.
  • On line 63, the other test method is tagged as TODO, since it is what needs to be fixed (and is expected to fail).

We will now look at how we can filter tests both in an IDE (IntelliJ IDEA) as well as during a build process (Apache Maven).

Filtering tests in IDE

When we run all tests in the IDE, screen shot below, ALL tests found are executed, which is not the ideal outcome since several tests marked TODO will fail.

JUNitRunAllTests

Run All Tests (in IntelliJ IDEA)

The Runner configuration can be edited. Select a Test Kind, with value Tags. In this example we used PASSING and TODO as the tags. We are trying to only run the PASSING tests, thus the Tag expression we use is PASSING.

JUNitRunConfiguration

Configure to Run tests with a specific Tag (in IntelliJ IDEA)

When this run configuration is executed, any test tagged as PASSING is included and executed. Tests without this tag (or with the TODO tag, in this example), are filtered out and ignored.

Filtering tests in a build

It is great to setup the IDE on a desktop to work as needed. Repeatability and automation drives using a build tool to do the same. We can also filter tests based on Tags using a build tool such as maven.

JUnit tests are executed in the test phase of the maven lifecycle. A common (and default) plugin to run unit tests is the maven-surefire-plugin. The plugin can be configured to include and exclude groups (generic name corresponding to tags in JUnit5, other unit test frameworks may have other names).

Example: pom.xml (https://github.com/c-guntur/java-katas/blob/baseline/pom.xml#L59-L67)

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.2</version>
                    <configuration>
                        <groups>PASSING</groups>
                        <excludedGroups>TODO</excludedGroups>
                    </configuration>
                </plugin>

In this example, when the maven build is run, any test with a Tag of PASSING is included and any test with a Tag of TODO is excluded.

Summary

In this blog, we saw how we could filter test class and test method names both dynamically using assumptions and more statically using Tags.

Hope this was helpful !

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

Using JUnit5 – Part 3 – Display Names

java, junit5

Published: 2019-07 (July 2019)
Relevant for: JUnit 5.5.0

JUnit5 Blog Series

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

In Part 1 of the blog series, we looked at several annotations used in JUnit5. We covered test methods as well as lifecycle methods.

In Part 2 of the blog series, we looked at the basics of testing using JUnit5. We covered test annotations such as marking a test method and asserting. We saw how a test method could be tagged and how assumptions can be used. We finally wrapped up with test execution ordering mechanisms.

This post will cover some customization of names for tests. First, a justification of why names should be customized.

Why customize names?

When test class with a few test methods is run with JUnit, the output produced lists the name of the class and a status of execution for each method. The name of the class is used as the top level identifier

JUnitNoDisplayName

As is visible from the image above, a JUnit test was run on a class STestSolution3PeriodsAndDurations. This has four test methods that were tested and they all verify something. All tests passed. However, one really has to peer into the names of all the tests to understand what they executed. For instance, the second test verifies creation of a Period using fluent methods. This was inferred and hopefully most developers name their test methods to convey meaningful intent to anyone who looks at the result.

Let’s compare that to the next image.

JUnitWithDisplayName

Clearly the latter image communicates a lot better about what was tested and what the intent was. The test class is replaced with a meaningful text of what the overall theme for all test methods enclosed was : “Periods (days, months, years) and Durations (hours, minutes, seconds)“. Also individual test methods had proper space-separated words rather than a camel-cased name.

Let’s now look at how we customize the names in JUnit5.

Customizing names in JUnit5

There are primarily two ways in which JUnit5 allows for customizing names.

  1. Using a @DisplayName on a test class or a test method.
  2. Using a @DisplayNameGeneration on the test class which accepts an attribute of a DisplayNameGenerator class.

DisplayName API: https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/DisplayName.html
DisplayNameGeneration API: https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/DisplayNameGeneration.html
DisplayNameGenerator API: https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/DisplayNameGenerator.html

Using a DisplayName annotation

Adding a @DisplayName annotation on a given class or test method can help customize a single class or method name. Let us look at examples.

DisplayName on a test class

Example: @DisplayName (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest3PeriodsAndDurationsTest.java#L35)

/**
* DateTime ranges: Period, Duration tests.
*
* Note: We create a Clock instance in setup() used for some of the tests.
*
* @see Clock
* @see Period
* @see Duration
* @see ChronoUnit
*/
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Periods (days, months, years) and Durations (hours, minutes, seconds)")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class STest3PeriodsAndDurationsTest {

DisplayName on a test method

Example: @DisplayName (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest2LocalAndZonedDateTimesTest.java#L304)

    @Test
    @Tag("PASSING")
    @Order(10)
    @DisplayName("verify conversion of UTC date time to Indian Standard Time")
    public void verifyConversionOfUTCDateTimeToIndianStandardTime() {

        ZonedDateTime allDateTimeOhFives =
                ZonedDateTime.of(5, 5, 5, 5, 5, 5, 555, ZoneId.ofOffset("", ZoneOffset.UTC));

        ZoneId gmtPlusOneZoneId = ZoneId.ofOffset("", ZoneOffset.of("+0530"));

        // DONE: Replace the ZonedDateTime.now() below to display the below UTC time in GMT +0530
        //  The ZonedDateTime created in GMT. Fix the calls so a ZonedDateTime
        //  can be created with the offset of GMT +0530. Use an ofInstant from a toInstant.
        //  Check: java.time.ZonedDateTime.ofInstant(java.time.Instant, java.time.ZoneId)
        //  Check: java.time.ZonedDateTime.toInstant()
        ZonedDateTime gmtPlusOneHourTimeForAllFives =
                ZonedDateTime.ofInstant(
                        allDateTimeOhFives.toInstant(),
                        gmtPlusOneZoneId);

        assertEquals(10,
                gmtPlusOneHourTimeForAllFives.getHour(),
                "The hour should be at 10 AM when Zone Offset is GMT +0530");

        assertEquals(35,
                gmtPlusOneHourTimeForAllFives.getMinute(),
                "The minute should be 35 when Zone Offset is GMT +0530");
    }

Using DisplayNameGenerator

Using a generator to modify display names is a two step process.

  1. Create a DisplayNameGenerator class.
  2. Set DisplayNameGeneration annotation on the Test class.

Setting up the DisplayNameGenerator

DisplayNameGenerator is an interface that has three methods with very sensible names that convey theor purpose:

  • generateDisplayNameForClass(Class<?> testClass) – This method can be implemented to provide a meaningful display name to the test class.
  • generateDisplayNameForNestedClass(Class<?> nestedClass) – This method can be implemented to provide a meaningful display name to a nested class in the test class.
  • generateDisplayNameForMethod(Class<?> testClass, Method testMethod) – This method can be implemented to provide a meaningful display name to a test method of a given test class.

Usage

DisplayNameGenerator is an interface, but has two out-of-the-box implementations that can be extended/adapted as needed.

  1. DisplayNameGenerator.Standard – converts camel case to spaced words.
  2. DisplayNameGenerator.ReplaceUnderscores – converts underscores in names as space-separated words.

The example extends the Standard implementation.

Example: DisplayNameGenerator (https://github.com/c-guntur/java-katas/blob/baseline/java-handles/src/main/java/none/cvg/handles/HandlesKataDisplayNames.java)

package none.cvg.handles;

import java.lang.reflect.Method;

import org.junit.jupiter.api.DisplayNameGenerator;

import static java.lang.Character.isDigit;
import static java.lang.Character.isLetterOrDigit;
import static java.lang.Character.isUpperCase;

public class HandlesKataDisplayNames extends DisplayNameGenerator.Standard {
    @Override
    public String generateDisplayNameForClass(Class<?> aClass) {
        return super.generateDisplayNameForClass(aClass);
    }

    @Override
    public String generateDisplayNameForNestedClass(Class<?> aClass) {
        return super.generateDisplayNameForNestedClass(aClass);
    }

    @Override
    public String generateDisplayNameForMethod(Class<?> aClass, Method method) {
        String methodName = method.getName();
        if (methodName.startsWith("reflection")) {
            return "using Reflection";
        }
        if (methodName.startsWith("unsafe")) {
            return "using Unsafe";
        }
        if (methodName.startsWith("methodHandle")) {
            return "using Method Handles";
        }
        if (methodName.startsWith("compareAndSet")) {
            return camelToText(methodName.substring(13));
        }
        if (methodName.startsWith("get")) {
            return camelToText(methodName.substring(3));
        }
        return camelToText(methodName);
    }


    private static String camelToText(String text) {
        StringBuilder builder = new StringBuilder();
        char lastChar = ' ';
        for (char c : text.toCharArray()) {
            char nc = c;

            if (isUpperCase(nc) && !isUpperCase(lastChar)) {
                if (lastChar != ' ' && isLetterOrDigit(lastChar)) {
                    builder.append(" ");
                }
                nc = Character.toLowerCase(c);
            } else if (isDigit(lastChar) && !isDigit(c)) {
                if (lastChar != ' ') {
                    builder.append(" ");
                }
                nc = Character.toLowerCase(c);
            }

            if (lastChar != ' ' || c != ' ') {
                builder.append(nc);
            }
            lastChar = c;
        }
        return builder.toString();
    }
}

Once a DisplayNameGenerator is created, the second step is to associate it with a test class. This requires using the @DisplayNameGeneration annotation on the test class.

Applying a DisplayNameGenerator

An annotation on a test class is required to avail of the generator logic. This is done by adding a @DisplayNameGeneration annotation on the test class.

Example: @DisplayNameGeneration (https://github.com/c-guntur/java-katas/blob/baseline/java-handles/src/solutions/java/none/cvg/constructors/SDefaultConstructorInvocationTest.java#L34)

package none.cvg.constructors;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

import none.cvg.handles.DemoClass;
import none.cvg.handles.HandlesKataDisplayNames;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import sun.misc.Unsafe;

import static none.cvg.handles.ErrorMessages.REFLECTION_FAILURE;
import static none.cvg.handles.ErrorMessages.TEST_FAILURE;
import static none.cvg.handles.ErrorMessages.UNSAFE_FAILURE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

/*
 * DONE:
 *  This test aims at using MethodHandles to invoke a default constructor on a class in order to
 *  create a new instance.
 *  Each solved test shows how this can be achieved with the traditional reflection/unsafe calls.
 *  Each unsolved test provides a few hints that will allow the kata-taker to manually solve
 *  the exercise to achieve the same goal with MethodHandles.
 */
@DisplayNameGeneration(HandlesKataDisplayNames.class)
@DisplayName("Invoke DemoClass()")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestSolutionDefaultConstructorInvocation {

Summary

In this blog, we saw how we could customize test class and test method names to produce a more meaningful output. The next blog will cover how we can filter tests based on tags.

Hope this was helpful !

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

Using JUnit5 – Part 2 – Testing Basics

java, junit5

Published: 2019-07 (July 2019)
Relevant for: JUnit 5.5.0

JUnit5 Blog Series

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

In Part 1 of the blog series, we looked at several annotations used in JUnit5. We covered test methods as well as lifecycle methods.

This post will share examples of a JUnit test which has a few of these annotations.

We will use a recently created code kata for the examples.

Testing

Marking a method as a Test

Tests in JUnit5 are annotated with the @Test annotation. Unlike prior versions of JUnit, the JUnit5 @Test annotation does not have any attributes. Prior versions supported extensions via attributes, while JUnit5 fosters a custom annotation based extension (more on this in a future blog).

Example: @Test (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest1InstantAndDateInteropTest.java#L43)

    @Test
    @Tag("PASSING")
    @Order(1)
    public void verifyInstantAndDateHaveSameEpochMilliseconds() {

        // DONE: Replace the Instant.now() with an instant from classicDate.
        //  Use a Date API that converts Date instances into Instant instances.
        //  Check: java.util.Date.toInstant()
        Instant instant = classicDate.toInstant();

        // DONE: Replace the "null" below to get milliseconds from epoch from the Instant
        //  Use an Instant API which converts it into milliseconds
        //  Check: java.time.Instant.toEpochMilli()
        assertEquals(Long.valueOf(classicDate.getTime()),
                instant.toEpochMilli(),
                "Date and Instant milliseconds should be equal");
    }

Assertions

Assertions are how testing is conducted. Several types of assertions exist for testing. Some examples include:

  • assertTrue / assertFalse
  • assertEquals / assertNotEquals / assertSame / assertNotSame
  • assertNull / assertNotNull
  • assertArrayEquals / assertIterableEquals / assertLinesMatch
  • assertThrows / assertNotThrows
  • assertAll
  • assertTimeout / assertTimeoutPreemptively
  • fail

There are several polymorphs for most of the methods listed above. JUnit5 aggregates all such assertions as static methods in a single factory utility aptly named Assertions (https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/Assertions.html).

Assertions are mostly unary or binary (There are assertions, with other arities, that are less commonly used)

Unary assertions are usually boolean condition evaluators. assertTrue or assertNull are good examples of unary assertions. The expectation in such cases is built into the actual assertion method name. A second optional parameter for unary assertions is a message that is returned in case of an assertion failure and exists to provide more meaningful readable failure details.

Binary assertions typically have an expected value (a known), an actual value (evaluated) and an optional third parameter of message (in case of the expectation not being met). assertEquals and assertSame are good examples of binary assertions.

Typically, unit tests statically import the assertions required for the given tests in a test class. An example of such an assertion is the assertEquals method as shown below.

Example: Assertion (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest1InstantAndDateInteropTest.java#L56)

    @Test
    @Tag("PASSING")
    @Order(1)
    public void verifyInstantAndDateHaveSameEpochMilliseconds() {

        // DONE: Replace the Instant.now() with an instant from classicDate.
        //  Use a Date API that converts Date instances into Instant instances.
        //  Check: java.util.Date.toInstant()
        Instant instant = classicDate.toInstant();

        // DONE: Replace the "null" below to get milliseconds from epoch from the Instant
        //  Use an Instant API which converts it into milliseconds
        //  Check: java.time.Instant.toEpochMilli()
        assertEquals(Long.valueOf(classicDate.getTime()),
                instant.toEpochMilli(),
                "Date and Instant milliseconds should be equal");
    }

See also: Static Import (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest1InstantAndDateInteropTest.java#L18)

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.TimeZone;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import static none.cvg.datetime.LenientAssert.assertAlmostEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

NOTE: Assertion parameter ordering in JUnit 5 is different from the order in prior versions. In my opinion, the current parameter arrangement makes a lot more sense.

Filtering and Categorizing Tests

Tags

Tags are a means to categorize test methods and classes. Tagging also leads to discovery and filtering of tests. Tagging is done by annotating the class or method with an @Tag annotation. More on filtering in another blog of this series.

Example: @Tag (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest1InstantAndDateInteropTest.java#L62)

    @Test
    @Tag("PASSING")
    @Order(1)
    public void verifyInstantAndDateHaveSameEpochMilliseconds() {

        // DONE: Replace the Instant.now() with an instant from classicDate.
        //  Use a Date API that converts Date instances into Instant instances.
        //  Check: java.util.Date.toInstant()
        Instant instant = classicDate.toInstant();

        // DONE: Replace the "null" below to get milliseconds from epoch from the Instant
        //  Use an Instant API which converts it into milliseconds
        //  Check: java.time.Instant.toEpochMilli()
        assertEquals(Long.valueOf(classicDate.getTime()),
                instant.toEpochMilli(),
                "Date and Instant milliseconds should be equal");
    }

Assumptions

Assumptions are conditions that determine if the rest of the test code block should be either evaluated or aborted. Not meeting an assumption will not cause the code block conditioned by it, to fail. It would rather simply abort execution of such a code block. Some assumption methods:

  • assumeTrue / assumeFalse
  • assumeThat

Similar to assertions, assumptions are grouped as static methods, in a factory utility class, Assumptions (https://junit.org/junit5/docs/5.5.0/user-guide/#writing-tests-assumptions).

class TestWithAssumptions {

    @Test
    void testOnlyOnHost123() {
        assumeTrue("host123".equals(System.getenv("HOSTNAME")));
        // remainder of test
    }

    @Test
    void testOnHost123OrAbortWithMessage() {
        assumeTrue("host123".equals(System.getenv("HOSTNAME")),
            () -> "Aborting test: not on host123");
        // remainder of test
    }

}

Typically, unit tests statically import the assumptions required for the given tests in a test class.

There is no current example of an assumption in the code kata.

Ordering Tests

Test execution order

As stated in the previous part of the blog series, I reserve my opinions of ordering the sequence of test executions. It is useful in certain cases, such as code katas. Test ordering requires either one or two steps depending on the type of ordering.

NOTE: If no order is specified for a test class, JUnit 5 looks for instructions from parent class hierarchy and if still none found, will order tests in a deterministic but non-obvious manner.

Instructing JUnit to order tests

An annotation on the test class is needed to instruct JUnit5 to order tests. This annotation is called the @TestMethodOrder. This annotation accepts an attribute of type MethodOrderer. There are three default implementations that exist:

  1. Alphanumeric – uses String::compareTo to order execution of test methods
  2. OrderAnnotation – uses the @Order annotation on each test method to determine order. The Order annotation accepts a int attribute that specifies the ranking.
  3. Random – uses a random order either simply from System.nanoTime() or in combination with a custom seed.

More custom orders can be created by implementing the MethodOrderer interface.

Example: @TestMethodOrder (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest1InstantAndDateInteropTest.java#L31)

/**
 * The tests in this class aim to show interoperability between
 * `java.util.Date` and the newer `java.time.Instant`.
 *
 * @see Instant
 * @see Date
 * @see LenientAssert
 */
@DisplayNameGeneration(DateTimeKataDisplayNames.class)
@DisplayName("Instant And Date Interoperability")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class STest1InstantAndDateInteropTest {

Extra Step (For OrderAnnotation only): Adding an Order via annotations

In addition to the above annotation instructing JUnit to order test methods, an additional annotation is needed if the OrderAnnotation orderer is specified. The @Order annotation accepts an integer that specifies the ascending order of execution.

Example: @Order (https://github.com/c-guntur/java-katas/blob/baseline/java-datetime/src/solutions/java/none/cvg/datetime/STest1InstantAndDateInteropTest.java#L45)

    @Test
    @Tag("PASSING")
    @Order(1)
    public void verifyInstantAndDateHaveSameEpochMilliseconds() {

        // DONE: Replace the Instant.now() with an instant from classicDate.
        //  Use a Date API that converts Date instances into Instant instances.
        //  Check: java.util.Date.toInstant()
        Instant instant = classicDate.toInstant();

        // DONE: Replace the "null" below to get milliseconds from epoch from the Instant
        //  Use an Instant API which converts it into milliseconds
        //  Check: java.time.Instant.toEpochMilli()
        assertEquals(Long.valueOf(classicDate.getTime()),
                instant.toEpochMilli(),
                "Date and Instant milliseconds should be equal");
    }

That’s a wrap of part two of this blog series. The next blog will include customizing tests with DisplayNames and writing a custom DisplayNameGeneration. Happy coding !

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

Using JUnit5 – Part 1 – An Introduction

java, junit5

Published: 2019-07 (July 2019)
Relevant for: JUnit 5.5.0

JUnit5 Blog Series

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

Code Katas are a great way of teaching programming practices. The effectiveness of a code kata is to “solve” something repeatedly in order to gain a “muscle memory” of sorts on the subject matter.

Nothing stresses repeatability more than unit tests. Code Katas thus, in many cases can be associated with or run via unit tests.

Many of us have been long used to JUnit4 as a formidable unit testing framework. This blog is not going to be a comparison between JUnit4 and JUnit5, but you will notice some differences as italicized text.

Let us explore JUnit5 as it was used for a recent code kata, this is how I learnt using JUnit 5 !

JUnit5 Logo

JUnit5 dependencies

JUnit5 can be added as a single maven dependency:

            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter</artifactId>
                <version>${junit5.version}</version>
            </dependency>

The equivalent gradle dependency can be inferred.

What is JUnit5 and What is Jupiter?

JUnit5 is made of three separate parts:

  1. JUnit5 Platform: Provides a TestEngine and a testing platform for the JVM.
  2. JUnit5 Jupiter: Programming and extension model for JUnit5 tests.
  3. JUnit Legacy: Backward compatibility TestEngine for JUnit 3 and 4.

Read more about this at the JUnit5 User Guide (https://junit.org/junit5/docs/current/user-guide/).

JUnit5 Basics

Base package for JUnit 5 is: org.junit.jupiter. Most unit test annotations are located at: org.junit.jupiter.apipackage (in the junit-jupiter-api module). Methods in JUnit5 Test can be typically grouped into :

  1. Test methods: Methods that are run as unit tests.
  2. Lifecycle methods: Methods that are executed as before or after one or more (or all) test methods.

Basic Annotations

@Test: Identifies a method as a test method. Unlike prior versions, this annotation does not have attributes. #TestMethod

@Disabled: An annotation to ignore running a method marked as @Test. #TestMethod

@BeforeEach: A setup method that is run before execution of each test. #LifecycleMethod

@BeforeAll: A static setup method run once before execution of all tests. #LifecycleMethod

@AfterEach: A teardown method this is run after execution of each test. #LifecycleMethod

@AfterAll: A static teardown method run once after execution of all tests. #LifecycleMethod

Other Annotations

@Tag: A category or grouping annotation. This is very useful specially when filtering which tests should be run via build tools such as maven. Example in another blog in this series.

@DisplayName: A string that can represent the class or method in the JUnit exection results instead of the actual name. Example in another blog in this series.

@DisplayNameGeneration: A class that can generate class and method names based upon conditions. Examples in another blog in this series.

Custom annotations: It is quite simple to create custom annotations and inherit the behavior.

JUnit5 Conditional Control of Test Methods

Operating System Conditions

@EnabledOnOs: Enable a test to run on a specific array of one or more operating systems.

@DisabledOnOs: Disable a test to run on a specific array of one or more operating systems.

Java Runtime Environment Conditions

@EnabledOnJre: Enable a test to run on a specific array of one or more Java Runtime Environments.

@DisabledOnJre: Disable a test to run on a specific array of one or more Java Runtime Environments.

System Property Conditions

@EnabledIfSystemProperty: Enable a test to run if a System Property matches the condition attributes.

@DisabledIfSystemProperty: Disable a test to run if a System Property matches the condition attributes.

Ordering Test method execution

JUnit5 allows for ordering test method execution. This causes mixed feelings for me.

My feelings: Ordering methods may lead to some developers building out dependent tests where the result of one test is needed for the next to run or pass. Tests should be independent. That said, it is an incredibly useful a feature when used in code katas where the run of tests may have to follow a certain sequence. In the past, I used to solve this by naming my test methods with some numeral-inclusive prefix and sort the results alphabetically. With great power, comes great responsibility.

@TestMethodOrder: Test methods can be ordered when the Test class is marked with this annotation.

@Order: Each test method can then include an Order annotation that includes a numeric attribute.

These were some of the basic that we covered. The next blog in this series will show examples of how we use these features.

Part 1 – Introduction
Part 2 – Test Basics
Part 3 – Display Names
Part 4 – Filtering tests

Using JUnit5 – The series

java, junit5

This is a series of blogs about JUnit 5 – a unit testing framework. This series is intended to be an introductory set of blogs to introduce, familiarize or brush up on JUnit 5.

The blogs in this series:

Part 1 – An Introduction
Bare Link: https://cguntur.me/2019/07/07/using-junit5-part-1/

Part 2 – Testing Basics
Bare Link: https://cguntur.me/2019/07/13/using-junit5-part-2/

Part 3 – Display Names
Bare Link: https://cguntur.me/2019/07/20/using-junit5-part-3/

Part 4 – Filtering Tests
Bare Link: https://cguntur.me/2019/07/27/using-junit5-part-4/

Devnexus 2019: Reflection and Unsafe alternates

java, java 11

As has been the norm for the past few years, I am very excited about attending Devnexus once again, in 2019. In my humble opinion, Devnexus is one of the best tech. conferences to attend. Devnexus is held in Atlanta, Georgia from March 6th – 8th 2019.

My presentation

I will be presenting on Friday, March 8th 2019, on the topic of Alternates to Reflection and Unsafe usage. This talk is a part presentation (small), part live coding kata session. Bring your laptop to participate in coding along – or – use a QR code scanner/scribbling device of your choice to capture the URL where you can check out the code to try out the coding portion later.

DaVinci

Details

Many Java libraries and frameworks currently use Reflection and Unsafe APIs. With the newer modular Java some of these important tools of our trade may become incompatible and/or may not work as desired. In addition several enterprise applications also rely on Core Reflection, (if not the use of Unsafe APIs).

Session

The essence of the session is to demonstrate the alternates for the current usage patterns for some of the simpler and more common usages of Java Reflection API and the sun.misc.Unsafe among applications, libraries and frameworks. An explanation of the newer Handles API will be followed with code that allows for a comparison between using both styles.

Oh, and spoiler alert: there may be an abridged fairy tale or two introduced during this talk.

Presentation

This presentation is intended for the application developers and is aimed at helping them both understand reflection and the newer alternates. This may further evolve into developers contributing to applications, libraries and frameworks in converting to the newer APIs.

The coding portion of this session is a code kata, that has two different kinds of unit tests. The code contains passing JUnit tests which show how Core Reflection and Usafe APIs were used, and failing tests using new light-weight Method and Var Handle APIs that the attendees can solve-along (or take as homework to work on).

Kata

A coding kata is best described THE Dave Thomas (Author of the The Pragmatic Programmer). Please do read his blog at http://codekata.com/. From Wikipedia:

 

A code kata is an exercise in programming which helps programmers hone their skills through practice and repetition.

How does one go about with this kata?

Steps:

  1. Run the test class(es).
  2. One or more tests will fail with the test failure message.
  3. Fix the failing tests by taking hints from the TODOs.
  4. Repeat above steps until all tests pass.
  5. Rinse and repeat (delete and checkout again, then back to Step 1) to build muscle memory.

Each test class has two types of test methods:

  • Solved test methods show how an invocation/access can be achieved with the traditional calls.
  • Unsolved/failing test methods which provide TODO hints that will allow the kata-taker to manually solve the exercise to achieve the same with MethodHandles/VarHandles.

How to prepare for coding along

This kata is developed as a Java maven project. Ensure that you have:

    1. Apache Maven 3.3.x or above. Tested with Apache Maven 3.5.0.
      Link: https://maven.apache.org/download.cgi

 

    1. JDK 11. Tested with OpenJDK 11
      Link: http://jdk.java.net/11/

 

    1. Your favorite Java IDE. IntelliJ IDEA Ultimate was used to develop this kata.

 

  1. Checkout the code from Github (link will be provided during the session).

Topics Covered

Reflection

Reflection is heavy weight. Reflection has been around in the Java space since almost 1997 (Java 1.1). Thanks to some futuristic changes in Java back in early 2000s, newer, more safe and more lightweight alternates are now available for almost all of the usages of reflection. Alternates to reflection using MethodHandles introduced in Java 7 are described.

The code kata covers constructor invocation and method calls to public, private, package-protected and protected methods. The solved examples show how invocations are performed using the Core Reflection API. The unsolved or failing tests that need to be fixed carry TODOs with hints explaining how to solve them and thus learn the newer MethodHandle API.

sun.misc.Unsafe

Unsafe is, well, unsafe. The sun.misc.Unsafe is a goto for developers (specially library and framework developers). Unsafe API allows for lower level memory modifications of fields and was the “solution” to atomic operations prior to the introduction of Atomic* classes. The Unsafe API also exposed some “dangerous” functionality, which will be covered.

The code kata covers getters, compareAndSet operations using Unsafe. The Kata also makes a distinction of what was supported in sun.misc.Unsafe, but is no longer allowed with the new VarHandle API.

Appendix

Some questions that usually popup during such a session including how the invocation happens, what the limitations are and how it all works. These are included in a more verbose appendix. A PDF copy of the presentation is included with the code. In addition, some of the features of Unsafe that cannot possibly be covered, given both the time limits of the presentation and the arrangement of the kata, are listed out in the appendix.


Take Away

The key take-away for an attendee of this presentation and kata is a solid understanding of the simpler and more common usages of Core Reflection API and Unsafe API alongside the newer Handles API both in similarity and in certain cases, how they differ.

Who knows if your next open source/enterprise contribution is with helping out a library, framework or an enterprise application in converting to the newer APIs ?

Java Method Handles – The NextGen Reflection

java, java 10, java 11, java 9, java10

Blog post date: 2018-06-10
Relevant Java Versions: Java 7+ (Method Handles were introduced in Java 7)

DukeReflection

Reflection was introduced in Java 1.1 (circa February 1997). Originally introduced as a tool for introspection, it quickly morphed into weapon to examine, introspect as well as alter both behavior and structure of a Java object, bypassing its member accessibility and instantiation rules. This feels very dangerous, and rightfully so, unless the application being built is a framework or a tool that is not fully aware of its operands and needs to dynamically bind such objects and work with/on them intimately.

JSR 292 (https://www.jcp.org/en/jsr/detail?id=292) a.k.a Multi-Language Virtual Machine (MLVM) and code-named: Da Vinci Machine Project, set out ease the implementations of dynamic language implementation and improve their performance, on the JVM. Core features that came to fruition thanks to the JSR:

  1. addition of a new invokedynamic instruction at the JVM level (helped dynamic type checking, the lambda support and performance improvements in other JVM languages, such as JRuby).
  2. ability to change classes and methods at runtime, dynamically (the focus of this blog).

The changes allowed for a lightweight reference to a method. A caller could thus, invoke a method through a method handle without knowing the method’s name, enclosing class, or exact signature, yet the call would run at nearly the speed of a statically linked Java call. These references are called MethodHandles.

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html

Intent

This blog post shows how Method Handles, as a more modern alternate to traditional reflection, can provide similar functionality to what we have come to expect from reflection.

Each section below will act upon a tester class to show how Method Handles work to replace or wrap around reflection calls.

The Invokable Class

The code is located at: https://github.com/c-guntur/reflection/blob/master/src/main/java/none/cgutils/InvokableClass.java.

Below is an excerpt of the code for the class that will be tested using both Reflection and Method Handles:

 1 public class InvokableClass {
 2 
 3     private String name;
 4 
 5     public InvokableClass() {
 6         this.name = "No param InvokableClass constructor";
 7     }
 8 
 9     public InvokableClass(String name) {
10         this.name = name;
11     }
12 
13     public String printStuff(String input) {
14         return "[" + this.name + "] - " + input;
15     }
16 
17     public String publicMethod(String input) {
18         return "[" + this.name + "] - Public method - " + input;
19     }
20 
21     public static String publicStaticMethod(String input) {
22         return "InvokableClass.class - Public static method " + input;
23     }
24 
25     private String privateMethod(String input) {
26         return "[" + this.name + "] - Private method " + input;
27     }
28 
29     protected String protectedMethod(String input) {
30         return "[" + this.name + "] - Protected method " + input;
31     }
32 
33     String packageProtectedMethod(String input) {
34         return "[" + this.name + "] - Package protected method " + input;
35     }
36 }

Invoking the default constructor

The code for default constructor invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/DefaultConstructorInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Default constructor via reflection";
 2 
 3         try {
 4 
 5             Class invokableClassClass = (Class) Class.forName("none.cgutils.InvokableClass");
 6 
 7             InvokableClass invokableClass = invokableClassClass.getDeclaredConstructor().newInstance();
 8 
 9             assertEquals("Reflection invocation failed", expectedOutput, invokableClass.printStuff("Default constructor via reflection"));
10         } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) {
11 
12             fail("reflection failure: " + e.getMessage());
13         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Default constructor via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of void (Constructor) and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(void.class);
 8 
 9         try {
10 
11             // Find the constructor based on the MethodType defined above
12             MethodHandle invokableClassConstructor = publicMethodHandlesLookup.findConstructor(InvokableClass.class, methodType);
13 
14             // Create an instance of the Invokable class by calling the exact handle.
15             InvokableClass invokableClass = (InvokableClass) invokableClassConstructor.invokeExact();
16 
17             assertEquals("Method handle invocation failed", expectedOutput, invokableClass.printStuff("Default constructor via Method Handles"));
18         } catch (NoSuchMethodException | IllegalAccessException e) {
19 
20             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
21             fail("findConstructor failure: " + e.getMessage());
22         } catch (Throwable t) {
23 
24             // invokeExact throws a Throwable (hence catching Throwable separately).
25             fail("invokeExact Failure " + t.getMessage());
26         }

Method Handles Explanation

Line 4: In the Method Handles excerpt, a lookup is setup. A Lookup is a factory to create method handles. A feature of method handles is that access restrictions are checked when the handle is created, rather than when they are used or invoked. This early access check requires that the access be evaluated against some potential caller. The Lookup acts as that caller. For this excerpt, a publicLookup is used (implies there is an alternate for non-public). A publicLookup has minimal access checks (more efficient, scope limited to public methods).

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandles.Lookup.html

Line 7: A MethodType is used to create a signature of the method intended to be looked up. The first parameter represents the return type class while the subsequent parameters (single, array or vararg of class types) represent the method parameters. The MethodType does not associate with the name of the method and is only concerned with types involved. A void return is represented by a void.class. Primitives are represented in a similar manner.

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodType.html

Line 10: A findConstructor is invoked on the publicLookup created earlier. The parameters are the type on which to find a constructor on, and a MethodType for picking up the right constructor signature.

Line 13: An invokeExact method ensures that the type checks defined in the MethodType are exactly matched. As in indicative by this name there are other similar methods which allow for a some fuzzyness.

API link: https://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html


Invoking a parameter constructor

The code for parameterized constructor invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/ParameteredConstructorInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[Constructor Demo] - Constructor via reflection";
 2 
 3         try {
 4 
 5             Class invokableClassClass = (Class) Class.forName("none.cgutils.InvokableClass");
 6 
 7             Constructor invokableClassConstructor = invokableClassClass.getConstructor(String.class);
 8 
 9             InvokableClass invokableClass = invokableClassConstructor.newInstance("Constructor Demo");
10 
11             assertEquals("Reflection invocation failed", expectedOutput, invokableClass.printStuff("Constructor via reflection"));
12         } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
13 
14             fail("reflection failure: " + e.getMessage());
15         }

Method Handles

 1         String expectedOutput = "[Constructor Demo] - Constructor via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of void (Constructor) and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(void.class, String.class);
 8 
 9         try {
10 
11             // Find the constructor based on the MethodType defined above
12             MethodHandle invokableClassConstructor = publicMethodHandlesLookup.findConstructor(InvokableClass.class, methodType);
13 
14             // Create an instance of the Invokable class by calling the exact handle, pass in the param value.
15             InvokableClass invokableClass = (InvokableClass) invokableClassConstructor.invokeExact("Constructor Demo");
16 
17             assertEquals("Method handles invocation failed", expectedOutput, invokableClass.printStuff("Constructor via Method Handles"));
18         } catch (NoSuchMethodException | IllegalAccessException e) {
19 
20             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
21             fail("findConstructor failure: " + e.getMessage());
22         } catch (Throwable t) {
23 
24             // invokeExact throws a Throwable (hence catching Throwable separately).
25             fail("invokeExact Failure " + t.getMessage());
26         }

Method Handles Explanation

Line 7: The MethodType has a return type of void.class (since it is a constructor) and also takes a String.class argument. This call will look for public method signatures of methods that accept a String input parameter and return a void.

Line 13: The invokeExact method has a varargs parameter signature, here a String used by the constructor is passed in


Invoking a public method

The code for public method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PublicMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Public method - via reflection";
 2 
 3         try {
 4 
 5             // Find the method on the class via a getMethod.
 6             Method publicMethod = InvokableClass.class.getMethod("publicMethod", String.class);
 7 
 8             InvokableClass invokableClass = new InvokableClass();
 9 
10             assertEquals("Reflection invocation failed", expectedOutput, publicMethod.invoke(invokableClass, "via reflection"));
11         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
12 
13             fail("reflection failure: " + e.getMessage());
14         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Public method - via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of String and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(String.class, String.class);
 8 
 9         try {
10 
11             // Public methods are searched via findVirtual
12             MethodHandle publicMethodHandle = publicMethodHandlesLookup.findVirtual(InvokableClass.class, "publicMethod", methodType);
13 
14             InvokableClass invokableClass = new InvokableClass();
15 
16             assertEquals("Method handles invocation failed", expectedOutput, publicMethodHandle.invoke(invokableClass, "via Method Handles"));
17         } catch (NoSuchMethodException | IllegalAccessException e) {
18 
19             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
20             fail("findConstructor failure: " + e.getMessage());
21         } catch (Throwable t) {
22 
23             // invoke throws a Throwable (hence catching Throwable separately).
24             fail("invoke Failure " + t.getMessage());
25         }

Method Handles Explanation

Line 10: Public methods are looked up using a findVirtual on the Lookup. The type being looked up, the name of the method and the MethodType (return values, input parameter types) are passed to the findVirtual.


Invoking a public static method

The code for public static method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PublicStaticMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "InvokableClass.class - Public static method via reflection";
 2 
 3         try {
 4 
 5             // Find the method on the class via a getMethod.
 6             Method publicStaticMethod = InvokableClass.class.getMethod("publicStaticMethod", String.class);
 7 
 8             assertEquals("Reflection invocation failed", expectedOutput, publicStaticMethod.invoke(InvokableClass.class, "via reflection"));
 9         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
10 
11             fail("reflection failure: " + e.getMessage());
12         }

Method Handles

 1         String expectedOutput = "InvokableClass.class - Public static method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup publicStaticMethodHandlesLookup = MethodHandles.publicLookup();
 5 
 6         // Search for method that: have return type of String and accept a String parameter.
 7         MethodType methodType = MethodType.methodType(String.class, String.class);
 8 
 9         try {
10 
11             // Public static methods are searched via findStatic
12             MethodHandle publicStaticMethodHandle = publicStaticMethodHandlesLookup.findStatic(InvokableClass.class, "publicStaticMethod", methodType);
13 
14             assertEquals("Method handles invocation failed", expectedOutput, publicStaticMethodHandle.invoke("via Method Handles"));
15         } catch (NoSuchMethodException | IllegalAccessException e) {
16 
17             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
18             fail("findConstructor failure: " + e.getMessage());
19         } catch (Throwable t) {
20 
21             // invoke throws a Throwable (hence catching Throwable separately).
22             fail("invoke Failure " + t.getMessage());
23         }

Method Handles Explanation

Line 10: Public static methods are looked up using a findStatic on the Lookup. The type being looked up, the name of the public static method and the MethodType (return values, input parameter types) are passed to the findVirtual.


Invoking a private method

The code for private method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PrivateMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Private method via reflection";
 2 
 3         try {
 4 
 5             // Cannot call getMethod(), only use getDeclaredMethod to get private and protected methods.
 6             Method privateMethod = InvokableClass.class.getDeclaredMethod("privateMethod", String.class);
 7 
 8             // Method has to be made accessible. Not setting this will cause IllegalAccessException
 9             // Setting accessible to true causes the JVM to skip access control checks
10             privateMethod.setAccessible(true);
11 
12             InvokableClass invokableClass = new InvokableClass();
13 
14             assertEquals("Reflection invocation failed", expectedOutput, privateMethod.invoke(invokableClass, "via reflection"));
15         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
16 
17             fail("reflection failure: " + e.getMessage());
18         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Private method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup privateMethodHandlesLookup = MethodHandles.lookup();
 5 
 6         try {
 7 
 8             // Rely on old-fashioned reflection.
 9             Method privateMethod = InvokableClass.class.getDeclaredMethod("privateMethod", String.class);
10 
11             privateMethod.setAccessible(true);
12 
13             // Unreflect to create a method handle from a method
14             MethodHandle privateMethodHandle = privateMethodHandlesLookup.unreflect(privateMethod);
15 
16             InvokableClass invokableClass = new InvokableClass();
17 
18             assertEquals("Method handles invocation failed", expectedOutput, privateMethodHandle.invoke(invokableClass, "via Method Handles"));
19         } catch (NoSuchMethodException | IllegalAccessException e) {
20 
21             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
22             fail("findConstructor failure: " + e.getMessage());
23         } catch (Throwable t) {
24 
25             // invoke throws a Throwable (hence catching Throwable separately).
26             fail("invoke Failure " + t.getMessage());
27         }

Method Handles Explanation

Line 4: Private methods can be looked up via lookup method call that has larger find radius than the publicLookup (i.e public as well as private/protected lookup).

Line 8: There is no equivalent to finding private methods, thus reflection is still needed to get to a Method instance of the private method. As with reflection, private method instances can only be invoked only after a setAccessible is set to true.

Line 11: Private method instances looked up via reflection need to be “unreflected” to convert from the java.lang.reflect.Method to java.lang.invoke.MethodHandle. There is no direct find equivalent for private methods.


Invoking a protected method

The code for protected method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/ProtectedMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Protected method via reflection";
 2 
 3         try {
 4             // Cannot call getMethod(), only use getDeclaredMethod to get private and protected methods.
 5             Method protectedMethod = InvokableClass.class.getDeclaredMethod("protectedMethod", String.class);
 6 
 7             // Method has to be made accessible. Not setting this will cause IllegalAccessException
 8             // Setting accessible to true causes the JVM to skip access control checks
 9             protectedMethod.setAccessible(true);
10 
11             InvokableClass invokableClass = new InvokableClass();
12 
13             assertEquals("Reflection invocation failed", expectedOutput, protectedMethod.invoke(invokableClass, "via reflection"));
14         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
15 
16             fail("reflection failure: " + e.getMessage());
17         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Protected method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup protectedMethodHandlesLookup = MethodHandles.lookup();
 5 
 6         try {
 7             // Rely on old-fashioned reflection.
 8             Method protectedMethodMethod = InvokableClass.class.getDeclaredMethod("protectedMethod", String.class);
 9             protectedMethodMethod.setAccessible(true);
10             // Unreflect to create a method handle from a method
11             MethodHandle protectedMethodHandle = protectedMethodHandlesLookup.unreflect(protectedMethodMethod);
12 
13             InvokableClass invokableClass = new InvokableClass();
14 
15             assertEquals("Reflection invocation failed", expectedOutput, protectedMethodHandle.invoke(invokableClass, "via Method Handles"));
16         } catch (NoSuchMethodException | IllegalAccessException e) {
17 
18             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
19             fail("findConstructor failure: " + e.getMessage());
20         } catch (Throwable t) {
21 
22             // invoke throws a Throwable (hence catching Throwable separately).
23             fail("invoke Failure " + t.getMessage());
24         }

Method Handles Explanation

Line 4: Protected methods can be looked up via lookup method call that has larger find radius than the publicLookup (i.e public as well as private/protected lookup).

Line 8: There is no equivalent to finding protected methods, thus reflection is still needed to get to a Method instance of the protected method. As with reflection, protected method instances can only be invoked only after a setAccessible is set to true.

Line 11: Protected method instances looked up via reflection need to be “unreflected” to convert from the java.lang.reflect.Method to java.lang.invoke.MethodHandle. There is no direct find equivalent for protected methods.


Invoking a package-protected method

The code for package-protected method invocation is located at: https://github.com/c-guntur/reflection/blob/master/src/test/java/none/cgutils/PackageProtectedMethodInvocationTest.java.

Excerpts that matter:

Reflection

 1         String expectedOutput = "[No param InvokableClass constructor] - Package protected method via reflection";
 2 
 3         try {
 4 
 5             // Cannot call getMethod(), only use getDeclaredMethod to get private and protected methods.
 6             Method packageProtectedMethod = InvokableClass.class.getDeclaredMethod("packageProtectedMethod", String.class);
 7 
 8             // Method has to be made accessible. Not setting this will cause IllegalAccessException
 9             // Setting accessible to true causes the JVM to skip access control checks
10             packageProtectedMethod.setAccessible(true);
11 
12             InvokableClass invokableClass = new InvokableClass();
13 
14             assertEquals("Reflection invocation failed", expectedOutput, packageProtectedMethod.invoke(invokableClass, "via reflection"));
15         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
16 
17             fail("reflection failure: " + e.getMessage());
18         }

Method Handles

 1         String expectedOutput = "[No param InvokableClass constructor] - Package protected method via Method Handles";
 2 
 3         // A look-up that can find public methods
 4         MethodHandles.Lookup packageProtectedMethodHandlesLookup = MethodHandles.lookup();
 5 
 6         try {
 7             // Rely on old-fashioned reflection.
 8             Method packageProtectedMethod = InvokableClass.class.getDeclaredMethod("packageProtectedMethod", String.class);
 9             packageProtectedMethod.setAccessible(true);
10 
11             // Unreflect to create a method handle from a method
12             MethodHandle packageProtectedMethodHandle = packageProtectedMethodHandlesLookup.unreflect(packageProtectedMethod);
13 
14             InvokableClass invokableClass = new InvokableClass();
15 
16             assertEquals("Reflection invocation failed", expectedOutput, packageProtectedMethodHandle.invoke(invokableClass, "via Method Handles"));
17         } catch (NoSuchMethodException | IllegalAccessException e) {
18 
19             // findConstructor throws a NoSuchMethodException and an IllegalAccessException,
20             fail("findConstructor failure: " + e.getMessage());
21         } catch (Throwable t) {
22 
23             // invoke throws a Throwable (hence catching Throwable separately).
24             fail("invoke Failure " + t.getMessage());
25         }

Method Handles Explanation

Line 4: Package-protected methods can be looked up via lookup method call that has larger find radius than the publicLookup (i.e public as well as private/protected lookup).

Line 8: There is no equivalent to finding package-protected methods, thus reflection is still needed to get to a Method instance of the package-protected method. As with reflection, package-protected method instances can only be invoked only after a setAccessible is set to true.

Line 11: Package-protected method instances looked up via reflection need to be “unreflected” to convert from the java.lang.reflect.Method to java.lang.invoke.MethodHandle. There is no direct find equivalent for package-protected methods.


There are a few other cool methods that will be covered in a subsequent blog.

Method Handles – Enhancements in Java Versions

    1. JSR-292https://www.jcp.org/en/jsr/detail?id=292Java 1.7 – Method Handles introduction.
    1. JEP-160http://openjdk.java.net/jeps/160Java 1.8 – Method Handles enhancements:
      • Improve performance, quality, and portability of method handles and invokedynamic.
      • Reduce the amount of assembly code in the JVM.
      • Reduce the frequency of native calls and other complex transitions of control during method handle processing.
      • Increase the leverage on JSR 292 performance of existing JVM optimization frameworks.
      • Remove low-leverage or complex structures from the JVM that serve JSR 292 only. (E.g., remove the pattern-matching “method handle walk” phase.)
      • Complete compatibility with the Java SE 7 specification for JSR 292.
      • A better reference implementation of JSR 292.
    1. JEP-274http://openjdk.java.net/jeps/274Java 9 – Method Handles enhancements (many API additions):
      • In the MethodHandles class in the java.lang.invoke package, provide new MethodHandle combinators for loops and try/finally blocks.
      • Enhance the MethodHandle and MethodHandles classes with new MethodHandle combinators for argument handling.
      • Implement new lookups for interface methods and, optionally, super constructors in the MethodHandles.Lookup class.

Complete Github project link: https://github.com/c-guntur/reflection

That’s a wrap on Java Method Handles – The NextGen Reflection (with more in a subsequent blog). Hope this post was helpful.

Switching between multiple JDKs on a Mac

java, java 10, java 11, java 8, java 9, technology

Blog post date: 2018-May-18
Relevant versions of Java: Java 1.7, 8, 9, 10, 11

We often work with different versions of Java. There are times when we would like to test our application/program against different JDKs. Or … we just love to collect all versions of Java released just to show off.

Either of these would mean some kind of control of the JAVA_HOME and the PATH environment variables.

MultiDuke

Many developers have successfully overcome this with innovative scripts to quickly switch Java versions. I am one such developer and below is an explanation of my setup.

Current installations of JDK on my Mac:

  • JDK 1.7.0_80
  • JDK 1.8.0_172
  • JDK 9.0.4
  • JDK 10.0.1
  • JDK 11-ea+14

How does one determine the current installations of JDK?

On your Mac terminal run the command:

/usr/libexec/java_home -verbose

Sample output:

Matching Java Virtual Machines (5):
11, x86_64: "OpenJDK 11-ea" /Library/Java/JavaVirtualMachines/jdk-11.jdk/Contents/Home
10.0.1, x86_64: "OpenJDK 10.0.1" /Library/Java/JavaVirtualMachines/jdk-10.0.1.jdk/Contents/Home
9.0.4, x86_64: "OpenJDK 9.0.4" /Library/Java/JavaVirtualMachines/jdk-9.0.4.jdk/Contents/Home
1.8.0_172, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_172.jdk/Contents/Home
1.7.0_80, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_80.jdk/Contents/Home

Simple ! Quite easy to determine the current JDKs available.

How can I switch Java versions easily?

Aliases. That’s it. If you know this, you can skip the remaining part of this blog. What is really cool is how a single JVM exec command can be used to switch JDK versions.

Sharing an excerpt from a .bash_profile:


alias jdk11="export JAVA_HOME=`/usr/libexec/java_home -v 11` && export PATH=$JAVA_HOME/bin:$PATH; java -version"
alias jdk10="export JAVA_HOME=`/usr/libexec/java_home -v 10` && export PATH=$JAVA_HOME/bin:$PATH; java -version"
alias jdk9="export JAVA_HOME=`/usr/libexec/java_home -v 9` && export PATH=$JAVA_HOME/bin:$PATH; java -version"
alias jdk8="export JAVA_HOME=`/usr/libexec/java_home -v 1.8` && export PATH=$JAVA_HOME/bin:$PATH; java -version"
alias jdk7="export JAVA_HOME=`/usr/libexec/java_home -v 1.7` && export PATH=$JAVA_HOME/bin:$PATH; java -version"

Note how the Java versioning from 9 onwards is a full digit? The same applies with the default directory names of the installed JDKs. This was a deliberate change toshake off the 1.x naming style of prior versions of Java.

JDK switching output

A picture would do this more justice.
Switching JDKs at Terminal

Maintenance of JDKs

Needs Admin rights on the Mac !

Keeping the JDK versions up-to-date is in everyone’s best interest, both for the new features as well as any security patches. A few steps that can help with maintaining:

    1. Extract the latest build/patch of the JDK into the directory: /Library/Java/JavaVirtualMachines.
      • If an installer was used, most likely the directories are created.
      • If a tarball was extracted from, make sure to move the extracted directory under the parent mentioned above.

 

    1. Post-installation, open a new terminal shell (current shell will not pick up the latest patch of an existing version of the JDK).
      • Add the appropriate alias, if this is a new version of Java
      • If existing version being patched, then no further action is needed.

 

    1. Type in the appropriate alias and verify that the build/patch is what shows.

 

  1. Once verified, the options for removing the prior patch present themselves:
    • delete older build/patch since it is no longer useful to reclaim space.
    • retain older build/patch, for other usage. It is possible to manually switch to this build/patch:
      • export JAVA_HOME=/Library/Java/JavaVirtualMachines/
      • export PATH=$JAVA_HOME/bin:$PATH

That’s a wrap on Switching JDKs on a Mac. Hope this post was helpful.