Thursday, July 10, 2014

Java8 fix for jaxws-maven-plugin

Today I can across an issue while trying to move a project to Java 8. The jaxws-maven-plugin we use to generate code from WSDL files. With Java8 this plugin caused this issue:
Exception in thread "main" java.lang.ClassCastException: java.lang.AssertionError cannot be cast to java.lang.Exception
  at org.jvnet.jax_ws_commons.jaxws.Invoker.main(Invoker.java:87)

This was a known issue already, but not fixed by anyone yet. So I decided to fix it myself.
The fix was rather easy: not case the exception anymore and update the maven-plugin-plugin dependency.

Then in our project, besides using the custom build jaxws-maven-plugin, I also had to update the jaxws-rt dependency to the latest version (2.2.10-b140319.1121) because an older version caused a NPE in AbstractJaxwsMojo.isArgSupported(..). I tried to remove this dependency completely because the JDK also has contains javax.xml.ws packages, but the AbstractJaxwsMojo does not support that (yet).

Since the jaxws-maven-plugin is still in a Subversion repo, I created a new Git repo with my fix which is available at https://bitbucket.org/diversit/jaxws-maven-plugin.

References:
Jaxws-common project home : https://jax-ws-commons.java.net/
Issue JAX_WS_COMMONS-129 : https://java.net/jira/browse/JAX_WS_COMMONS-129
Jaxwx-commons source code : https://java.net/projects/jax-ws-commons/sources/svn/show

Friday, June 6, 2014

Loading dynamic Angular content via JQuery

Sometimes you cannot start a project from scratch. Sometimes you're just stuck with crap created by others. And often you want to improve that.

Say, you're stuck with a web application full with JQuery (created in some not to be named country in South Asia starting with 'I' and ending with 'ndia') and you are really trying to make something better of it. You don't understand anything of this Indian JQuery magic, so you gradually replace it with some clear, tested! and short Angular code.

You created a nice Angular component, added it to your application, but somehow it works in one page but not on another. After some debugging you notice that when the component doesn't work, it is in some html fragment which is dynamically loaded using 'ajaxSubmit' function from JQuery's Form plugin. This dynamic loading is outside of Angular's scope, so Angular does not know this is happening and therefore cannot do any Angular stuff on the new fragment.

The trick to solve this, is to 'compile' the new html fragment using Angular and then insert it into the DOM. This gives Angular the opportunity to activate any Angular components in the fragment. Now, the big question is, how to do this 'compiling' ? Let's go through it step by step.

Before

This was how it was before
$(this).ajaxSubmit({target:'#body',url:'/my/mvc/url'});
This replaced the content of the html tag with id 'body' (so not the contents '<body>' tag itself!) with the html returned by the url '/my/mvc/url'.

Calling an Angular function from plain JavaScript

Somehow the returned html fragment must be compiled, so we need a function which call's Angular's compiler and pass the new html. But, JQuery cannot access Angular's providers or services, so the function must be in Angular. For JQuery to be able to access the function, you must put it somewhere where JQuery can reach it. At first I put the function on Angular's $rootScope like this:
app.run(function($rootScope) {

    $rootScope.refresh = function() {
        console.log('refreshing body');
    }
});
You can then reach this function by getting the rootScope like this:
var rootScope = angular.element(document).scope();
rootScope.refresh();
You can even get the scope of an element by adding a find('') before the 'scope()':
var elementScope = angular.element(document).find('elemId').scope();
elementScope.refresh();
This also works because an Angular Scope inherit from it's parent Scope. The 'app.run' function is called when the page is loaded so it creates the function on the object at that time.

I did not like this solution, because you have to get the scope first before you're able to call the wanted function. So, I opted for another solution to put the function on the Window object so the function would be globally available. In Angular you can just add the $window argument to a function and then create a new function on that object which can then be called from anywhere in JavaScript.
app.run(function($window) {

    $window.refresh = function() {
        console.log('refreshing body');
    }
});

Compile the new html fragment

Angular has a $compile provider with which you can compile the html fragment.
Using it is as easy as adding the '$compile' argument to the run function. The html can be passed as an argument and the return value is the compiled html which you can then put into the dom.

Adding it to the dom

Somehow adding the html to the dom correctly wasn't very straight forward. An element supports both a 'replaceWith' and a 'html' method to modify is contents, but using:
elem.replaceWith( $compile( newHtml )(elemScope))
displayed the html wrong.
elem.html( $compile( newHtml )(elemScope))
This did not work at all.
Finally:
$(target)['html']( $compile( newHtml )(targetScope));
this seemed to work fine.
For me, it all looked like the same code, just written differently, but apparently it makes a difference.

Calling compile function from ajaxSubmit

Initially, the 'ajaxSubmit' call would 1) call the url and 2) replace the content of the provided target with the new html. Because we have to compile the html before it can be injected, a success handler is required to capture the retrieved data. Then it can be compiled and added to the dom.
$(this).ajaxSubmit({
  // no target! Angularfy function will put code into dom.
  url:'&lt;@core.basePath/&gt;my/mvc/url',
  success: function(data) {
    // call the compile function and add compiled html to dom.
  }
});

The full solution

Putting everything together, this is the solution I ended up with. The 'angularfy' function compiles the html and adds it to the provided target.
app.run(function($window, $compile) {

    /*
     * Function to 'Angular-fy' dynamically loaded content
     * by JQuery. This compiles the new html code and injects it
     * into the DOM so Angular 'knows' about the new code.
     */
    $window.angularfy = function(target, newHtml) {
        // must use JQuery to query for element by id.
        // must wrap as angular element otherwise 'scope' function is not defined.
        var targetScope = angular.element($(target)).scope();

//        elem.replaceWith( $compile( newHtml )(elemScope)); Displays html wrong.
//        elem.html( $compile( newHtml )(elemScope)); Does not work.
        $(target)['html']( $compile( newHtml )(targetScope)); // Does work!
        targetScope.$apply();
    }
});
In the web page, the ajaxSubmit calls the 'angularfy' function from the success handler.
$(this).ajaxSubmit({
  // no target! Angularfy function will put code into dom.
  url:'&lt;@core.basePath/&gt;my/mvc/url',
  success: function(data) {
    angularfy('#body', data); // to notify Angular of new html code in dom.
  }
});

Happy Angular-JQuery-ing ! ;-)

Btw: I am a hardcore Java/Scala backender and do not pretend to be a frontend/Angular guru. This solution might not be the nicest one, but for me, at this moment, it works. If you know any improvements, let me know.

Wednesday, May 28, 2014

Java 8's Optional frustrations

At my current project we started working with Java 8 this week. Mainly because of the new Streaming Api so we could do some functional coding in Java and get rid of the Google Guava dependency (which I kind of introduced some weeks ago, because, well, I just hate doing for-loops and null-checks. Once you’ve done Scala you don’t want to go back ;-).
Being used to work with Scala’s Option, I eagerly got started to remove all null-checks and start working with Java’s Optional. The Optional is a nice addition but after working with it for a few days I feel it is dead-wrong in 2 basic and primary methods:

1. To create an Optional, you use Optional.of(..). I threw in a value which could be null and immediately got a NPE. Apparently there is an Optional.ofNullable() method. WTF!! I cannot think of any reason why the ‘of’ method should not accept null’s. Why oh why would you otherwise want to use an Optional if you know the value is never null ! Having to use ‘ofNullable’ is just unnecessary typing and is polluting the code. The ‘of’ method is just useless.

2. Working with requests and contexts, I sometimes want to get one attribute, but, if it’s not set, I want to fall back to another attribute which also might not be set. So, I want to create an Optional and use ‘orElse’ to use another optional value. However, in Java the Optional.orElse returns ’T’ and not an ‘Optional<T>’. In contrast to Scala's Option which ‘orElse’ does return ‘Option[T]’. The ‘Optional.orElse’ method is really a ‘getOrElse’ returning the value of the Optional or an alternative. A real ‘orElse’ function is just missing. I don’t want the value T, I want to keep working with the Optional in a functional way. Now, to get around this you have to do something like this:
Optional.ofNullable(Optional.ofNullable(getValueA()).orElse(getValueB())). How is that for readability? 

Besides these clear mistakes (IMHO) I regret the Optional has not found it’s way into some other classes, like a Map.getOptional method for example, to be able to get Optional instances right away instead of having to do the wrapping yourself.

Friday, April 19, 2013

WebDav4Sbt version 1.2 released

Today version 1.2 of the WebDav4Sbt plugin was released.
This version fixes an issue with publishing Ivy artifacts to WebDav. Thanks to Flanker_9 for raising the issue.

To publish an artifact Ivy-style instead of Maven add to your _build.sbt_:

    publishMavenStyle := false

For more info, see the WebDav repo: https://bitbucket.org/diversit/webdav4sbt.
I got the permission to add my plugin to the plugins list on sbt-scala.org. Although I am very busy at the moment, I'm going to try to do this soon.

Saturday, March 23, 2013

New Webdav4Sbt release adds crossPaths support

Version 1.1 of the Webdav4Sbt plugin was just released.
The new version adds support for publishing Java artifacts which do not need the Scala version in the artifact name. To remove the Scala version from the Java artifact name, add to your build.sbt:

    crossPaths := false

Thanks to jplikesbikes for this contribution.

See the Webdav4Sbt plugin site for more info.

Monday, March 4, 2013

Integration test support merged in Jacoco4Sbt plugin

Yesterday Joachim merged the Integration Test Support changes I made into the jacoco4sbt plugin and he released version 2.0.0 of the plugin.

To use this plugin version, add to your project/plugings.sbt:

    addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.0.0")

And to the build.sbt:

    import de.johoop.jacoco4sbt._

    import JacocoPlugin._

    seq(jacoco.settings : _*)     // for unit test coverage
    seq(itJacoco.settings : _*)  // for integration test coverage

See my previous post about how to enable integration testing with sbt.

Wednesday, February 27, 2013

Publishing from SBT to WebDAV (CloudBees)

This week I was trying to setup a Jenkins in the Cloud using CloudBees to learn about building SBT projects in a CI environment. I had just forked and adjusted the Jacoco4Sbt plugin (see my previous post) and wanted to build and host this project somewhere in the cloud. CloudBees provides an excelent service for this and when using Dev@CloudBees it is also free.

The whole setup of Jenkins on CloudBees is pretty easy. As well as building the project using SBT.
The problem was however, how to deploy the artifacts to the CloudBees Maven repository which is available via WebDAV. Apparently, the SBT publish task does not create the required directory structure on a WebDAV target location, so the publish task failed.

While Googling around I could not find a better solution then to create those directories by hand either by mounting the WebDAV locally or by using Curl. At first I used Curl to create the directories after which the artifact could successfully be published, but I was not happy with this solution. What if I change the organization, name or version of the project? Then I would have to create those directories manually again. The whole goal of an automated build/deploy system is, that everything works automatically.

So ... I created a new SBT plugin which I called: WebDav4Sbt.

The goal of this plugin is to automatically create those directories needed on a WebDAV location so the artifacts can be published. The plugin uses Sardine, a Java WebDAV client, to implement the WebDAV MKCOL command to create the WebDAV collections (a.k.a. directories).

The plugin adds 2 new tasks for SBT:
* mkcol  -  A tasks which creates the publish directories
* publish  -  The adapted default publish task which automatically calls mkcol so the required directories are always available.

See the WebDAV4Sbt project page for info on how to add this plugin to your project and use it.

I am working on a bigger article on how to setup a CI environment in the cloud in which I will share how I setup the CI to host, build and publish Scala projects using BitBucket and CloudBees. I hope I can publish it somewhere next week.