Friday, April 25, 2014

I Have a Little Gradle...

and a buildfile I will code

and when it’s done and tested

to Ant and Maven I’ll say “no!”

Lately, one of my projects at work has been to switch our odd little Buildenstein’s Monster build scripts from a toxic stew that includes Ant (shudder) over to a pure Gradle design.

Gradle is a neat little tool. If Ant is insipid, annoying Justin Beiber and Maven is stodgy, mannered inflexible Bach, then Gradle is some sort of free jazz like Eric Dolphy that is sort of irritating, but you can still (occasionally grudgingly) admire the freedom and brilliance behind its freedom, flexibility and deviation from the norm.

So far, the project has been a rousing success. We’ve had to work through a lot of edge cases in places where Gradle’s behavior is just sort of odd and funky (I’ll write about those in the future!). The IDE support also is not nearly as good as Maven’s. While IntelliJ IDEA seems to leverage Maven’s limited set of rather shitty functionality perfectly, its Gradle support is less than inspiring (it’s often a lot quicker to use the Gradle tasks from the command line than from the IDE).

One thing that I do miss from Maven is its concept of a provided scope. Essentially, this means that a project requires a certain dependency at compile time, but it should not be included in packaging or distribution.

This is particularly important when deploying a project to an environment that has an existing implementation of that dependency, or when the dependency is an interface that relies on an external implementation. This is the case for the Java Servlet API and Hibernate, among other things. (There is also an optional scope in Maven, which I’ve never used, but surprise, users want this in Gradle too!)

Unfortunately, for Java programmers, this scope (providedCompile) is only available for the war plugin, not the Java plugin. This is actually a fairly serious omission, as all of the hair pulling and clothing tearing over at the going-on-five-year-old, heavily-upvoted JIRA issue requesting this feature and associated GitHub pull request show.

Indeed, a Google search for just the JIRA issue name reveals absolutely tons of build.gradle files that implement the various not-quite-satisfactory workarounds for the lack of a proper provided scope while praying one day for a satisfactory resolution to the issue (I wonder how many buildfiles out there do this without referencing the issue name!).

The odd thing is that the last time this was raised on the gradle-dev mailing list, it was met with the sound of crickets; not a single bite.

One thing I hate is boilerplate code, and all of these various hacks to add this functionality are basically boilerplate code, because literally every Java project that I have ever done has needed a scope for compile-time dependencies that shouldn’t be packaged.

The Gradle team has rightfully underscored the importance of not blindly including everything that Maven has without thought, but at the same time there has been little thought or discussion put towards providing this very basic, widely-used piece of functionality, All the while, the votes on the issue grow and users implement one or more of these cheesy workarounds, adding to their legacy code burden while there is already a pull request for the functionality.

Long story short: WTF?

EDIT: Lest I come across as unhelpful, here I’ll link to some of the better solutions to the Gradle team’s oversight:

  • the Spring propdeps-plugin: I know, I know, Spring. Amirite? No need to worry though, since this is just a Gradle plugin that provides the optional and provided dependency scopes, you won’t have to worry about including a gigabyte of transitive dependencies for simple functionality, like when you include anything Spring with your Java code.
  • The best provided answer from the Gradle Forums: Notice that the Gradle developer who marked it ‘answered’ made no attempt to clarify or vet either of the solutions proposed.
  • A further elaboration of the solution above. This is what I myself do until the Gradle team gets its act together.

Using Jackson's Mixins to Deseralize to Guava's Immutable Collections

Using Jackson to Deseralize to Guava’s Immutable Collections With Mixins

Lately, I’ve been querying some RESTful web services using the potent Jackson/Jersey combination. The data returned by the (not strictly public or documented) API in question has a bad case of irritating data element naming.

I didn’t want to pollute my object classes with the same stupid names, so my first thought was to use the @JsonProperty annotation:

public class Foo {
    @JsonProperty(value="LOLSTUPIDNAME")
    private String value;

    // Stupid Java Getters/Setters :( 
    // Java team pls add properties like C#
}

Unfortunately, this has the side effect of polluting your object classes with implementation details, like which deserializer I am using. What if I want to switch from Jersey to GSon (LOL)?

Luckily, Jackson also offers a solution with a typically-java level of needless verbosity with Mix-Ins. This means that I can put those annotations in a separate (almost duplicate :( ) class to whisk those implementation details out of my POJOs!:

My POJO

public class Foo {
    private String value;

    // Needlessly Verbose Java Bullshit Getters/Setters
}

Mixin!

public class FooMixin {
    @JsonProperty( value="LOLSTUPIDNAME" )
    String value;
}   

Registering the Mixin in Association With the Object Class

We also have to make Jackson aware of this association. Yeah, this is kind of gross, but hey, Java, where programmer pain isn’t nearly as important as saving a tech writer five lines in the product README by eliminating PermGen.

Programming in Java is like having that good friend from college who always acts in horrible ways but you just shrug and say “Hey, that’s Jeff”.

Well, “Hey, that’s Java”.

Anyway.

public class MyProjectMapperProvider implements ContextResolver<ObjectMapper> {
    private static ObjectMapper mapper = new ObjectMapper();

    static {
        mapper.registerModule( new MyProjectModule() );
    }

    @Override
    public ObjectMapper getContext( Class<?> blah ) { return mapper; }
}

public class MyProjectModule extends SimpleModule {

    @Override 
    public void setupModule( SetupContext ctx ) {
        super.setupModule();
        context.setMixInAnnotations( Foo.class, FooMixin.class);
    }
}

Now this is all well and good, but I sort of want to return Guava’s immutable collections instead of Java’s default mutable ones. Luckily, there is already a module that knows how to deserialize into these immutable collections!

Unfortunately, this doesn’t work:

POJO

public class Foo {
    private List<Qux> values;

    // Needlessly Verbose Java Bullshit Getters/Setters
}

Mixin

public class FooMixin {
    @JsonProperty( value="LOLSTUPIDCOLLECTION" )
    ImmutableList<Qux> values;
}   

Apparently, Jackson takes the type from the POJO class, not the Mixin class (This seems like a bug to me).

Fortunately, this DOES work (after we register the Guava module similarly to registering MyProjectModule):

Mixin

public class FooMixin {
    @JsonProperty( value="LOLSTUPIDCOLLECTION" )
    @JsonDeserialize(as = ImmutableList.class)
    List<Qux> values;
}   

Sweet! Anyone have a better way to do this?