Monday, February 29, 2016

Maven testing module

My usual practice is to put test dependencies in my Maven parent POM when working on a multi-module project. And I usually have a "testing" module as well for shared test resources such as a logback-test.xml to quiet down test output.

The test dependencies look like clutter in my parent POM, and they are, or so I recently realized.

As all my non-test modules use the "testing" module as a test dependency, I clean this up by moving my test dependencies out of the parent POM and into the "testing" module alongside the common resources. So my layout looks like:

Parent POM
Common properties such as dependency versions, dependencies management marks the "testing" module as "test" scope.
Testing POM
Test dependencies not marked as "test" scope—consumers of this module will mark it as "test", and its transitive dependencies will automatically be "test" as well.
Non-test POMs
Use the "testing" module as a dependency—specified in the parent POM dependencies management—, no test dependencies or resources inherited from parent POM.

Examples:

Thursday, February 25, 2016

Java 8 shim method references

So I'm working on Spring Boot autoconfiguration for Axon Framework. I run into a nice interface in Axon framework that is unfortunately too specific. So I generalize. The original, pared down:

public interface AuditDataProvider {
    Map<String, Object> provideAuditDataFor(CommandMessage<?> command);
}

Aha! A SAM interface, interesting. So I craft my look-a-like:

public interface AuditDataProvider {
    Map<String, Object> provideAuditDataFor(Message<?> command);
}

Not much difference. Note the method parameter is Message rather than CommandMessage. This works fine as the implementation I have in mind uses getMetaData(), defined in Message and inherited by CommandMessage—so the original Axon interface is overspecified, using a more specific parameter type than needed.

(Keep this in mind: most times use the most general type you can.)

Ah, but other parts of the Axon framework ask for an AuditDataProvider (the original code, above) and I'm defining a new, more general interface. I cannot extend the original with mine; Java correctly complains that I am widening the type: all CommandMessages are Messages, but not all Messages are CommandMessages.

Java 8 method references to the rescue!

public interface MessageAuditDataProvider {
    Map<String, Object> provideAuditDataFor(final Message<?> message);

    default AuditDataProvider asAuditDataProvider() {
        return this::provideAuditDataFor;
    }
}

Because I accept a supertype in my new interface relative to the original, my method reference works simply and cleanly.

Sunday, February 21, 2016

Followup: Feature Toogles for Spring

The original technique in Spring Techniques: Feature toggles for controller request handler methods works well in the small but failed for our large project. We have too many snowflakes, customized replumbing of Spring and Boot, and destructive interference forced another path. So we went with AOP, the magical fallback in such situations, a pity.

But help is on the way!

The Togglz project is close to an official solution for the 2.3.0 release (no timeline announced). I am pleased with the solution taken and contributed a small bit. Here's the documentation commit. Please try 2.3.0-RC1 when it goes to Maven Central.

Modern maven

I've pushed my first release of Modern-J, a maven archetype (project starter), to github. Mostly this is for myself, to have a decent maven archetype for starting spikes and projects.

One thing I learned about maven is dealing with version mismatch in dependencies. The technique is not to modify <dependency> blocks with exclusions but to add a <dependencyManagement> block:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

(My POM sets "junit.version" to 4.12.)

This resolves the dependency mismatch between current JUnit (4.12) and the JUnit for System-Rules (4.11), a wonderful JUnit @Rule I hope to see eventually bundled with JUnit itself.

UPDATE: Hat tip to Qulice who beat me there first, though I'm not as strict.

Sunday, February 14, 2016

Java generic exception specifiers

I'm not sure it's widely appreciated that throws clauses can take generic parameters, just as return type or arguments. You can leverage this to improve your error handling. Note the helpful type inference provided by the compiler:

public final class ErrorHandlingMain {
    public static void main(final String... args) {
        final Result<String, RuntimeException> fooResult
                = success("foo");
        final Result<String, Exception> barResult
                = failure(new IOException("bar")); // Note #1

        out.println(fooResult.get());  // Note #2
        out.println(get(fooResult));   // Note #3
        try {
            out.println(barResult.get());  // Note #4
        } catch (final Exception e) {
            out.println(e);
        }
        try {
            out.println(get(barResult));
        } catch (final Exception e) {
            out.println(e);
        }
    }

    public static <T, E extends Exception>
    T get(final Result<T, E> result)
            throws E {
        return result.get();
    }

    @FunctionalInterface
    public interface Result<T, E extends Exception> {
        T get()
                throws E;

        static <T> Result<T, RuntimeException>
        success(final T value) {
            return () -> value;
        }

        static <T, E extends Exception> Result<T, E>
        failure(
                final E exception) {
            return () -> {
                throw exception;
            };
        }
    }
}

(Unusual formatting to help with screen width.)

  1. Note type widening from IOException to Exception. Reversing those types won't compile.
  2. Compiler sees RuntimeException, does not require try/catch.
  3. Likewise for static methods.
  4. Compiler sees Exception, requires try/catch.