High Sierra and Jar to App

Previously I posted a simple Gradle snippet to create an app bundle from a jar file. Well the resultant apps stopped working with a recent OS X update.  I tinkered with it but in the end I could not avoid getting a strange launchd error messages in /var/log/system.log every time I double clicked the bundle.

However, the standalone tool jar2app was creating app bundles that still worked fine.  I really didn’t want to have to use another tool as a post process though.  So, I tore open jar2app and pulled the keys bits out and managed to swap them in. I’m not going to walk through all of it again, most of the old notes still apply, so if you’re interested read the prior post and then take a look at the new code with the fixes.

Advertisements

Spring Boot and Kotlin, Implementation

I’ve mentioned I used Kotlin to implement a Spring Boot service, here are the bits and pieces needed to make this work.  To briefly recap, I had to quickly implemented a service as a proof of concept so went with Kotlin’s Spring Boot integration. It proved to be really easy and as I’ve continued work with the service I’ve been more and more happy the choice.

The Build Bits

I use gradle as the build tool, so lets start with whats needed there.

There’s a lot required, yes, but no particular magic. To make Spring Boot work you need the collection of plugins and dependencies above.  Some of these are a little creepy, in particular the kotlin-allopen dependency used to circumvent some of Kotlin’s clean code features to allow for Spring Boot’s inelegant hijinks.

What does this get you?  With that build.gradle you’ll be able to develop in Kotlin, use Spring annotations, and run familiar build tasks like gradle bootRun. Additionally, gradle bootRepackage will create a single jar file, including all the Kotlin dependencies, that lets you run the service with java -jar as expected.

Heres my gradle.properties with the versions I used as an up to date and compatible suite:

The Noteworthy Code

The Application class in Kotlin:

Very straight forward. With that in place you’ve now got the best of both worlds.  You can write all your code in Kotlin, but annotate it with Spring annotations, for example a For example, a controller might look like:

 

 

Spring Boot and Kotlin

Sometimes Spring Boot seems like a DNA virus, getting into everything and fundamentally corrupting it.  But there it is front and center, widely adopted.  I’m not a fan but I’ve used it often when employers asked or when I had to spit out a quick proof of concept.

Last week I had to write a custom status service at work, we needed a quick visual map of the health of the environments for a dashboard. The requirements were simple but didn’t easily work with any existing tool I found out there.  So I hacked a Spring Boot service to do what we needed.

But, I decided to add a spoonful of sugar, and implemented it with Kotlin’s Spring Boot support. And wow did the medicine go down smooth.  It was actually fun to write, the Spring Boot support was well done, and I ended up with a full fledged Spring Boot service, implemented with fairly idiomatic Kotlin.  Nice.  I’ll follow up here in another post with notes on the implementation – but just wanted to say – this was a win.

JDK 11 … JDK Version Burnout

I’ve started seeing articles about Java 11, and my reaction is really?!  I’m working mostly in version 8.  I’ve done proof of concept work in 9’s new features like modules. I’m building mostly with 10 because the general wisdom is jump to 10 since it’s out. Now I’m seeing traffic on 11.

All that said, it’s common for candidates I interview to be unfamiliar with key additions in 7 let alone 8.

This is just ridiculous.  I’m going back to my Kotlin.

Kotlin: When is a Lambda Not a Lambda?

Answer: When it’s inlined. Or at least sort of.

How So?

I encountered a “list” interface as follows:

Not much of a list right? I wanted to traverse the list and when one of the Nodes met some criteria return it. As an example:

That worked. But I thought I could do it more idiomatically so I tried:

Obvious fail! I mean at first glance it kinda looks right but the return from inside the lambda can’t work! Or can it?  It can if you add inline to the function.

Because then the lambda stops being a lambda it’s just an inline block and the return works fine.

How do I Feel About This?

It’s cool, but sort of confusing too.  I’m not sure if I’m happy that when I use a lambda I can’t be sure how it will behave unless I look at the code I’m passing it too. So yeah… it’s good and bad I guess.

 

Continuing Kotlin

Kotlin has definitely gotten under my skin, I’ve really taken to the language.  It’s a robust language that improves my code consistently, making it cleaner and easier to read.  The syntax is clean, mostly avoiding syntactic saccharin, and incorporating OO and functional paradigms harmoniously.  Higher order functions are done well incorporating closures beautifully.  Performance seems good. Build times are quick.  A lot of bad memories of the early days of Scala are contrasted by my Kotlin experience.

The One Soft Spot

Generally I’ve found the tool chain in good shape, but as I consider advocating adoption for larger projects I’ve one concern: code coverage.  When you’re working with a large project that should have a longer life, code quality is important. You can race through early sprints, delivering a slew of features, and feeling really positive.  But if your code is sloppy, your tests lacking, velocity will start to slow and you’ll find you’re spending most of your effort dealing with mess as opposed to making new progress.

You can avoid this by employing a unicorn team of only responsible rock stars.  I’ve been on that team once or twice.  But, more likely, you’ve got a mixed bag of people, and you need to develop quality.  A good language is a good start, but to improve over time you need to be able to continuously evaluate your work and learn from it.  Code coverage tools can really help there.

Kotlin has partial JaCoCo and Sonar support.  It works in Codacy. But, hopefully those or tools similar will improve because  I think Kotlin is awesome and want to be able to advocate it even to the uninitiated.

Creating an OS X App Bundle With Gradle

I’ve been tinkering with Kotlin and JavaFX and the result was a Java jar file that spins up a user interface.  OS X will double click open a jar, but I wanted a normal app. I looked around and found App Maker, which did a decent job, but processing the jar manually each build got annoying fast.  Looking at the info out there, and what App Maker did, it seemed like I ought to be able to get gradle to do the same without too much pain. I did.

The Simplest App Possible

So, from documentation, and investigating App Maker’s output, the simplest app is:

AppName.app/
   Contents/
      Info.plist
      MacOs/
         AppName-x.y.z.jar
         launcher
      Resources/
         application.icns

That’s the basics.  So if you’ve a working jar, all you’re lacking it the directory structure, and:

  • Info.plist: An Apple plist file, you can use a simple one unaltered.
  • launcher: A shell script that launches the jar. This can be 98% templated, with only things like the app name, jar name, and java version needing to be set.
  • application.icns: An icon formatted to Apple’s approval.

The Gradle Solution

To generate the app bundle from gradle, I did two things:

  1. Put the three needed files into src/main/app. The Info.plist and the application.icns are the actual final files.  The launcher I modified into a template, using Ant’s templating notation “@VARIABLE_NAME@”.
  2. Then I added one gradle task to build out the directory structure, and copy the files into place, applying the templating.

The Task

Here is the gradle task.  I employed some of gradle’s ant support to perform copies and templating.

With the files and task in place all you need to do is run gradle osxApp and you’ll hopefully find build/app/ProjectName.app – a working OS X app.

Conclusion

I could roll this into a Gradle PlugIn but that’s more work then I want to do for this.  As it stands, if you want to use this approach, just grab my project that uses it, copy the files in src/main/app and add the task to your build.gradle.