June 25, 2016

New software release: SubWay – Batch video channel downloader



Having talked a lot about software development in general in this blog, I’ve now finally released a piece of software which may be genuinely useful for an actual end-user. I hereby present SubWay, an automated YouTube channel batch video downloader, as freeware.

Note: In this blog post, I’ll talk about the background of developing the SubWay software from a software engineering point of view. If you’re just interested in downloading and using SubWay, please head over to its download page. It’s free :-)

About

YouTube has become a great place to watch high-quality video content online. There are a few apps which allow downloading YouTube videos, which is great as well. However, I always felt there was one piece missing: A software which not only lets you download a single or many videos, but which watches for new video releases on the channels you’re interested in, and downloads them automatically. This is exactly what SubWay does: Add channels to your favorites – search for new videos – download them. Again, head over to its download page to see it in action.

So I really wanted to create a software which I personally thought to be genuinely useful. I then decided to release it as freeware such that others may use it as well.

When compared to similar software products, SubWay provides this one unique feature, and it was my goal to realize it in a very user-friendly manner. This includes an easy-to-use GUI, an alternative command line client to support scheduled automation, and config files stored in a human-readable JSON format.

Implementation

SubWay actually doesn’t realize any video download functionality itself – it doesn’t even talk to the internet in any way. Instead, it relies on the youtube-dl command line tool which does the talking to online servers. All SubWay does really is invoking youtube-dl with the appropriate command line parameters, managing files, doing the appropriate calculations, and, of course, displaying the GUI.

It was in fact after I discovered the existence of the youtube-dl tool that I decided to create a download manager on top of it – I’ve never been interested in developing the complex YouTube API consumption myself, and reusing the youtube-dl functionality seemed like a great way to save me from reinventing the wheel (apart from the obvious legal issues).

Hence, the actual implementation work of SubWay mainly consisted of these parts:
youtube-dl process invocation and parsing of its JSON output
  • Developing the appropriate model entities and match them against youtube-dl output
  • Implement the actual business logic, the heart piece of which is the logic which checks for newly-released videos per channel which haven’t been downloaded yet.
  • Building the GUI
  • Building the command line client

Technology

As a professional Java developer, using a JVM technology stack was a natural choice for me. Given that the underlying youtube-dl program is written in Python, a Python implementation would have been favorable, but I literally don’t know anything about that programming language.

In fact, I implemented about 10% of functionality in Java 8, and 90% in statically-typed Groovy. Implementing the business logic in Groovy tremendously increased ease of development, code readability and maintainability. A while back, I created a blog post about the main reasons to use Groovy in a project.

Of course, this technology choice implied that the resulting fat JAR file would increase by about 400% to > 8.5MB. Considering the application is targeting a PC with enough disk space to store hundreds of video files, this issue seems negligible. As far as performance is concerned, I haven’t observed any impact which could be attributed to Groovy.

The GUI is implemented with JavaFX 8.

JSON serialization / deserialization for youtube-dl output as well as for config files uses the Jackson XML parser. Of late, I’ve written a blog post about the Groovy / Jackson combination.

Command line parsing makes use of the Apache commons cli package.

Finally, I used ProGuard for code shrinking / obfuscation.

Where’s the source code?

So far, I’ve used this blog to discuss topics related to software engineering, and to publish open source software projects which I hope to have some educational value for fellow software developers; and I will continue to use my blog this way in the future.

However, this project is different. This is the first time I created a proper “end-user” software which I think may be considered useful by a broad audience. Also, this is the first “bigger” project I ever realized using JavaFX, and I certainly have yet a lot to learn about this technology. During development, I have really concentrated on creating actual functionality, and less on creating interesting abstractions or using interesting programming techniques. I think thus that educational value of this software currently is low, and I don’t feel like the code quality reaches the usual standards of my open source projects yet.

Hence, I decided to not publish the software open source.

However, I built a few general-purpose library functions in Groovy, and I may publish them open source soon.

Development experience

Major development effort has been demanded by the following tasks:
  • External process handling
  • JSON deserialization
  • JavaFX
  • ProGuard code obfuscation, especially in combination with Groovy / JavaFX

External process handling

Invoking and consuming the youtube-dl.exe process has been quite challenging to implement; most of all because it is naturally very uncomfortable to test as in the end, you really need that actual output from the program running against the YouTube API.

The actual functionality consists of running the external process, consuming its output in real-time or as a whole, triggering callbacks, checking the sterr for errors, allowing the caller to abort the process, and doing all these things in a background thread such that the callbacks can update the UI in real time.

This needs interplay of different standard components of Java and Groovy. I eventually abstracted this to a helper class. I will publish this open source soon.

JSON deserialization

JSON deserialization happens in two places: When consuming youtube-dl’s JSON output (e.g. video information) and when loading the application’s settings files. I really wanted to store the settings in JSON format to stay (expert) user friendly.

I tried out different JSON frameworks before finally discovering that Jackson does its job really well with a minimum amount of configuration required.

JavaFX

I’m quite new to JavaFX 8 and a lot of trouble I’ve had building the GUI clearly can be explained by lack of experience. However, I still think that quite a few aspects of the framework seem… fishy, to say the least. I’ve posted a rant about Lambdas, and another one about Java 8 Promises, and I feel like there’s much room for yet another rant about JavaFX 8.

As JavaFX is here as the successor of Swing (which clearly needs a more modern-looking alternative), I expected the programming model to be much superior in every aspect. However, I found so far that this is not the case:
  • The FXML editor (which by the way is no longer shipped with the JDK) really only assists basic GUI building. The good ol’ Swing editor in NetBeans at least supported proper Java code generation (e.g. action methods).
  • The whole “data binding” story seems to be of very limited use, and its API is as bad as that of lambdas.
  • The components have in general a quite strange API, somehow similar to Swing, but yet different, and especially proper layouting is in no way simpler than in Swing.
  • A good portion of the API just doesn’t seem to make any sense at all. They tried to build an MVC-like programming model, but it is so bad that we still fall back to procedural Swing-style coding.
Maybe I’m just spoiled from clean, well-designed (server-side) Java enterprise frameworks.

I seriously consider creating a minimalistic helper framework for dealing with JavaFX. For now, my GUI code mainly consists of a collection of hacks and workarounds.

ProGuard code obfuscation

After I decided to release this program closed-source, it became apparent that I needed a means of obfuscating the resulting JAR.

Here, the use of Groovy clearly made things more complicated, even in strict statically-compiled mode. I finally decided to really only obfuscate / shrink my own code, rather than trying to shrink the whole fat JAR (including the sources of Groovy and other 3rd party libs), which however turned out to be uncomfortably challenging to realize using Maven as the build tool.

Another setback was to find that Java FX’s FXML files apparently make it impossible to apply code obfuscation as it breaks connection between the FXML and the Java code.

I decided to use ProGuard for the actual obfuscation. It’s free, highly configurable in terms of what to keep and what to obfuscate, and it can be integrated in Maven builds. On the other hand, the actual quality of code obfuscation is more or less set, and doesn’t allow for much configuration.

Conclusion

I’ve now released the very first public beta version of SubWay, v. 0.1-beta. Feel free to head over to its download page, try it out and give me feedback in the comments. I hope to build an updated version soon.

In the meantime, I will continue to discuss all kinds of software development-related topics on this blog. Thank you for your interest.

June 19, 2016

Angular 2: Official tutorial projects in ES6 + TypeScript + seed! (part 3 of 3)


Pages: 1 2 3

How to set up an Angular 2 project: TypeScript

Here, I expect you to have set up an ECMAScript-based Angular 2 project based on above explanations already and that now you’re interested in moving towards TypeScript.

I cannot decide whether a TypeScript-based implementation is right for you.
  • TypeScript’s static typing can be an important and useful safety net, especially in more complex projects. If you come from a statically typed language such as Java, you may find this environment more familiar. TypeScript also adds a few syntactic enhancements on ECMAScript 6.
  • On the other hand, static typing can be perceived as an impediment, especially when coming from the JavaScript world or when used to a typical “rapid application development” environment. Note that TypeScript really is a product, not a standard.
I encourage you to try out both setups, and decide for yourself.

And again: reading this chapter is completely optional. You can just take the tutorial project as a skeleton and start writing your business code.

In the following section, I will only show the steps where a TypeScript setup derives from the ECMAScript setup presented above.

Generate skeleton

Again, you may use Yeoman to generate the project skeletton (or start with the completed ECMAScript setup, as we built it earlier).

Project structure

Same as in the ECMAScript section, except that the following additional folder will be generated during the build:
  • typings: Generated by npm (typings). Contains the *.d.ts type definition files.

npm dependencies

See the complete package.json file here.

We make a few changes to the earlier ECMAScript setup:
  • Add reflect-metadata: a TypeScript-specific runtime dependency.
  • All the babel… parts are removed, of course, as we do not transpile using Babel, but using the TypeScript compiler.
  • Instead, of course, add TypeScript’s dependencies: typings (plus the grunt-ts task).
Note that for convenience, we define a postinstall action for npm:
"postinstall": "typings install"
This will get invoked after
npm install
(But not yet; make sure to first finish TypeScript setup, as described below.)

Grunt setup

See the complete Gruntfile.js file here.

Here of course, we replace the Babel transpilation steps by their TypeScript equivalent.
  • This is done through the setup in initConfig(). Make sure to specify that the tsconfig file should be consulted as well.
  • Invoke ts on deploy and live reload.

Transpilation config

See the complete tsconfig.json file here.

The tsconfig.json file is the TypeScript equivalent of Babel’s babel.rc file:
{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": true,
    "suppressImplicitAnyIndexErrors": true
  },
  "exclude": [
    "node_modules",
    "typings/main",
    "typings/main.d.ts"
  ]
}
You can usually stick with the example file here. Make sure that both "emitDecoratorMetadata" and "experimentalDecorators" are set to true!

See the complete typings.json file here.

Did I mention already that TypeScript is statically typed?

Imagine that we write TypeScript code, and then we import it. That’s not a problem, because TypeScript code is statically typed, hence type information is there, in the code.

However, external modules distributed trough npm are compiled to plain old ES5 code. There’s no type information, and that’s a problem.

The solution comes through the typings project which provides type definitions (*.d.ts files) for all npm modules (at least, that is the ultimate goal). In the package.json file, we defined to run download and installation of the type definitions at build time.

In the typings.json file, we define where to download type definitions for all 3rd party libraries in use.

For a simple Angular 2 project, you at least need to provide Angular 2’s type definitions:
{
    "globalDependencies": {
        "core-js": "github:DefinitelyTyped/DefinitelyTyped/core-js/core-js.d.ts"
    }
}
Otherwise, transpilation will fail due to lack of type definitions.

SystemJS runtime module dependency config

See the complete systemjs.config.js file here.

We can completely reuse the configuration from the ECMAScript setup.

index.html

See the complete index.html file here.

Again, this is the same as in the ECMAScript setup, apart from one difference:
  • We need to additionally import the reflect-metadata library which is a TypeScript-specific runtime dependency.

JavaScript runtime bootstrapping

See the complete main.ts file here.

No changes to the ECMAScript equivalent. Note that like all JavaScript files, because we’re writing TypeScript, the file ending is now *.ts.

The main app component

See the complete app.component.ts file here.

No changes to the ECMAScript equivalent.

Additional components

See the app/scripts directory here.

Just as described in the ECMAScript section. Again, note these syntactical changes in TypeScript:
  • Don’t forget to explicitly declare interfaces using implements statements.
  • You can make use of the private keyword.
  • There’s the more concise TypeScript constructor syntax constructor(private http: Http) { } over constructor(http: Http) { this.http = http; }.

Server startup

See the complete package.json file here.

See the explanation in the ECMAScript section.

Conclusion

With this blog post, I hope I have presented fellow AngularJS developers with a comprehensive guide to take the first step towards Angular 2 – setting up a project. I hope that the two project skeletons may serve you as a comprehensible starting point to build a clean, sound Angular 2 project setup. With the main focus on the ECMAScript 6 step, I hope they help lower the hurdle to get started with Angular 2 – and maybe even animate to look into TypeScript.

In fact, having an ECMAScript and a TypeScript setup side-by-side I find quite interesting. It shows that switching from one to the other isn’t that hard, and it serves as a live example of the pros and cons of each technology (although we didn’t delve too deep into that in this article).

I’m really curious about Angular 2, and I will gladly continue investigating this new technology in future blog posts, and hopefully adapt these project seeds according to new knowledge I gain.

Please share your thoughts about this article, and the project seed repositories, in the comments section below. If you have expert knowledge in some of the technologies used by the seed projects, your contributions on GitHub are highly welcome!


Pages: 1 2 3


Angular 2: Official tutorial projects in ES6 + TypeScript + seed! (part 2 of 3)


Pages: 1 2 3

How to set up an Angular 2 project: ECMAScript  6 / 7

Here I will explain how to setup an Angular 2 project from scratch. This is actually based on my experience setting up the tutorial projects described above. It may be helpful to refer to the tutorial project setup while reading through this chapter. By explaining the exact steps needed to create an Angular 2 project, I hope to “break its magic”, providing you with a deeper understanding of what is really going on under the hood.

Of course, reading this chapter is completely optional. You can just take the tutorial project as a skeleton and start writing your business code.

Note that this chapter is not a strict step-by-step tutorial. Project build / startup will probably fail unless all of below steps are completed.

Generate skeleton

We will start with a typical AngularJS project setup which I assume you are familiar with. You can e.g. use the Yeoman AngularJS generator to scaffold a simple AngularJS project:
yo angular

Project structure

Here I use this project structure:
  • Main folder: Contains all the project configuration files
  • app folder: Contains the actual business code
    • index.html: The Single Page Application umbrella HTML page
    • scripts folder: Contains the business code, written in ES6
    • pages folder: Contains the HTML pages (views)
    • styles folder: Contains the CSS files
  • node_modules. Generated by npm. Contains the npm dependencies.
  • dist
    • scripts: Generated by babel. Contains the transpiled ES5 JavaScript code.

npm dependencies

See the complete package.json file here.

The package.json file defines the project’s dependencies. We install all the tools we need into the local node_modules folder in order to become independent of the machine’s build tools setup.

Note some of these essential dependencies:
  • @angular…: As of Angular 2 RC-1, the Angular root package has changed from angular2 to @angular.
  • A few of Angular 2’s own runtime dependencies, as discussed later, including the SystemJS dependency management runtime library.
  • babel…: Babel transpiles ES6 to ES5 at build time. Note that we need a few additional plugins to enable some experimental features. We’ll discuss these later.
  • A few additional build time dependencies, mostly for Grunt (including the grunt-babel task).
Install the dependencies with
npm install

Grunt setup

See the complete Gruntfile.js file here.

Starting off with an AngularJS-like Grunt setup (as e.g. generated by running yo angular), we need to apply these changes to fit it for use with Angular 2:
  • Configure Babel which does the transpilation from ES6 to ES5 during the build:
    • Set it up in initConfig(). Note that we provide additonal options through the .babelrc file (see below).
    • Register it for running during server startup (run / default)
    • Register it for running during server live reload (watch)
  • Expose the appropriate file paths to the web (serveStatic).
    • Most importantly, we will expose dist/scripts (the transpiled scripts), systemjs.config.js (the SystemJS config, see below), and node_modules (as imposed by usage of SystemJS, see below).
  • Angular 2 by default uses “HTML 5 mode” for routing, i.e. instead of using <a> anchors (# in the URL), an actual redirect / UL redirect is faked. In order for that to work, we must redirect all requets on the server side. This is achieved by using the 'connect-modrewrite' plugin for Grunt.
If you feel more comfortable with an alternative build tool, e.g. Gulp, you can use it instead.

Transpilation config

See the complete babel.rc file here.

As mentioned earlier, we use Babel to transpile ES6 code to ES5 such that the browser can read it.

Note that in the example project setup, transpilation happens as an additional build step which is for many reasons to be preferred over transpiling on-the-fly in the browser. We need to transpile our own code only, not external modules (node_modules) as these typically come in plain old ES5 already through npm.

We set up Babel in the build configuration file. Additional configuration goes into the babel.rc file which is implicitly applied:
{
  "plugins": [
    "angular2-annotations",
    "transform-decorators-legacy",
    "transform-class-properties",
    "transform-flow-strip-types"
  ],
  "presets": [
    "es2015"
  ]
}
  • First and foremost, we need to specify the main "es2015" preset which will apply all the necessary transformations to turn ES6 code into ES5.
However, in order to make full use of Angular 2’s syntax, we need to enable support for some additional experimental syntactical elements:
  • Angular 2 makes heavy use of so-called Decorators (e.g. @Component({…})) which, although part of TypeScript, are a mere experimental proposal for future ECMAScript (we’re even talking about ES6’s successor ES7 here). Although we could write Angular 2 code without them, they make the syntax much cleaner. Thus we enable them with the 3rd party "transform-decorators-legacy" plugin.
  • Angular 2 ‘s dependency injection logic is based on typed constructor parameters where the type (a.k.a. class) of a parameter is used to resolve a dependency. In ES6 (and ES7), there is no notion of a type system. Thus comes the "angular2-annotations" plugin, which fakes typed parameters.
  • Conveniently, "angular2-annotations" also enables us to specify fields on ES6 classes which is not supported by native syntax.
Note that although these enhancements make it more easy to write concise Angular 2 syntax, we are technically not writing standard-compliant ES6 code any more now.

There may be similar configuration steps for alternative transpilers such as Traceur.

SystemJS runtime module dependency config

See the complete systemjs.config.js file here.

As in the official examples, we will use SystemJS as a module dependency management system here. It will resolve module dependencies as requested by import / export statements.

Note that in this configuration, Babel ES6 to ES5 transformation runs first, and module dependencies are actually resolved in the resulting ES5 files at runtime.

SystemJS configuration happens in the systemjs.config.js file. Here, SystemJS is instructed how to link between package names and the respective JavaScript library.

Unless you need 3rd party libraries, you can typically just reuse the example config file for any of your AngularJS projects.

If you don’t like SystemJS, you can use a browser dependency management tool of your choice instead, e.g. Bower or Webpack.

index.html

See the complete index.html file here.

This is the entry page of an Angular 2 single page application. Because all content is dynamically rendered in this page, it is typically the only place where we need to define the HTML <header>.

These are the essential parts for a working Angular 2 application:
  • <base href="/"> is required for routing / navigation (@RouteConfig) in “HTML 5 mode”.
  • A number of 3rd party scripts need to be imported. These are described in the Angular 2 documentation. To sum up:
    • zone.js: A runtime dependency for asynchronous computation
    • rxjs: Another runtime dependency for asynchronous computation
    • systemjs: The SystemJS runtime dependency (see above)
  • Then, there are the two local SystemJS scripts:
    • The systemjs.config.js config file import (see above)
    • The actual execution of importing the main application module through SystemJS (see below) as an inline script
  • In the <body>, we simply insert the selector of our main component (see below), plus a placeholder to be shown during application startup.

JavaScript runtime bootstrapping

See the complete main.js file here.

In index.html, the SystemJS import of the main module
System.import('app')
is resolved within systemjs.config.js to load the main.js file
'app': { main: 'main.js',  defaultExtension: 'js' },
which does the actual bootstrapping of the Angular 2 application:
bootstrap(AppComponent, [
    ...
]);
This refers to the application’s main component (see blow) and injects dependency providers on which it depends.

You can take the example main.js file as a template for your own applications, and adjust module imports / the dependency provider list accordingly.

The main app component

See the complete app.component.js file here.

AngularJS component files typically have this structure:
  • imports from other JavaScript files
  • Metadata decorators
    • In the case of a component, typically @Component({…})
    • In the case of the main component, typically also @RouteConfig([…]) for the router / navigation configuration.
    • In the case of a service, typically just @Injectable()
  • The actual component as an exported class
    • Thanks to the "angular2-annotations" Babel plugin (see above), we can define fields on a class.
    • If the component’s logic needs an external component / service, these must be explicitly defined and set in the constructor.
By convention, the main component should be named AppComponent and be registered to the my-app selector.

The latter is what renders this component in lieu of the <my-app> placeholder in index.html.

If your application needs routing (sub-pages), don’t forget to include <router-outlet></router-outlet> where you want the content of the current route to be rendered. This is typically placed in the main component’s HTML template.

Additional components

See the app/scripts directory here.

Even more than AngularJS, Angular 2 promotes a very modular programming model. You should try to follow this by keeping the main application component free of any business logic and implement the latter in separate, dedicated components and services, one per JavaScript file.

For the actual implementation part, you can follow Angular 2’s official TypeScript tutorials even if you use ECMAScript 6 / 7. Most of the syntax is nearly identical, except for a few differences:
  • Interfaces are not supported and actually useless (because there’s no static typing). Simply delete all implements… declarations.
  • The private keyword is not supported. Simply delete it.
  • As a consequence of the above: The more concise TypeScript constructor syntax constructor(private http: Http) { } is not supported. You have to explicitly do constructor(http: Http) { this.http = http; } instead.

Server startup

See the complete package.json file here.

The package.json file specifies the start script:
"start": "grunt serve"
Thus, start the server with
npm start
Pages: 1 2 3

Angular 2: Official tutorial projects in ES6 + TypeScript + seed! (part 1 of 3)



I created a complete project skeleton based on Angular 2’s official “QuickStart” and “Tour of Heroes” tutorial code samples, and ported them to ECMAScript 6 / 7. Feel free to download them, or read on for Angular 2 project setup instructions.

As an AngularJS developer, I am naturally interested in what is branded as its successor and “the future of web development”. So I started my journey with the official tutorials.

Although these are accompanied by brilliant code samples, what I really wanted was seeing them integrated in a complete project setup as one would see it in a real world project. That’s why I decided to build the official tutorial code samples into an actual project skeleton.

This article discusses:
Feel free to skip to the section which interests you.

Nomenclature note: As in the official documentation, I will refer to the former 1.0 version of Angular as AngularJS, and to the future release 2.0 as Angular 2. Furthermore, I will use ES6 to refer to ECMAScript 6 + experimental features of ECMAScript 7, and ES5 as an abbreviation of ECMAScript 5 (i.e. current browser JavaScript).

Also note that I use the term “official” here to refer to the “official” Angular 2 tutorials which provide parts of the source code of the project setup I am presenting here. I am not affiliated with the Angular 2 project.

The official tutorials, revised

Note that the following are improvement suggestions which I subsequently realized. It’s not my intention to suggest that Angular 2’s original tutorials are bad, much in the contrary, but they didn’t fulfill all my expectations.

ECMAScript and TypeScript

Although Angular 2 proudly (and rightfully) states that their framework works in both plain JavaScript and TypeScript (and Dart), and with the official release date approaching, they have so far neglected to port their official tutorial applications to ECMAScript 6.

Why would I care about ECMAScipt? The Angular 2 website really suggests that TypeScript is the successor of current JavaScript (ECMAScript 5). But it is not. That’s what ECMAScript 6, and 7 is. That’s the official standard. TypeScript is an implementation, and an extension, of that standard. Most importantly and famously, it adds static typing. But that’s just an optional addition.

I believe in gradual adaptation. I think when coming from AngularJS’s pure JavaScript world, ECMAScript 6 should be the next step in order to understand why and when it makes sense to leap even further towards TypeScript. That’s why I decided to port the examples to ECMAScript 6 / 7.

(But I created a complete skeleton with TypeScript as well.)

A build tool

As desribed in the “QuickStart” tutorial GitHub README: “This is not the perfect arrangement for your application. It is not designed for production.”, and “We are unlikely to accept suggestions about how to grow this QuickStart into something it is not.”

This clearly refers to the fact that unlike typical real-world projects, as the average AngularJS developer is expecting to see them, the official tutorial setup comes without a build tool. Rather, the TypeScript compiler is invoked directly via npm, and the code is published to a small “development only” local server.

This, I think, is unfortunate also as it increases coupling between the TypeScript environment and the build process.

Instead, I introduced Grunt, well-known to most AngularJS developers, to handle build and deployment of the application. Of course, you could replace it with the build tool of your choice.

Directory structure

Again: The official tutorial is not set up with production-readiness in mind. I really wanted to bring some structure to the file organization in this project. Most importantly, user-written and transpiled code should be clearly separated.

A clean setup

Finally, I found that due to the fast pace of Angular 2’s development, and the quick succession of new releases, some of which introduce breaking changes, the demo project’s setups (plural, as there are a few of them) aren’t quite up to date, and their configuration doesn’t seem consistent. Therefore, it was my aim as well to present an up-to-date project configuration. (At the time of writing, this is 2.0.0-rc.2 (2016-06-15).)

The official tutorials as a project setup seed

I have built two versions of a complete Angular 2 project setup, based on the source code of two of Angular 2’s official tutorials:
  • The 5 min “QuickStart” tutorial, as discussed here and referred to as the starting point for other official tutorials.
  • The “Tour of Heroes” tutorial, as discussed here, presenting the most important components of Angular 2.
Indeed, there are in general no other changes from one project to another than the actual example business JavaScript / HTML / CSS source code.

According to above reasoning about building a project seed, I have been following roughly these steps to setup the project:
  • Run the Yeoman generator to create an empty AngularJS (sic!) project.
  • Set up the Grunt build tool.
  • Set up the necessary transpilation tasks (see below).
  • Upgrade everything to the newest version (build tools, libraries).
  • Integrate the official tutorial’s source code, as presented in its live Plunker version, into the project.
For each of these projects, I have created a version written in ECMAScript 6 / 7 (which transpiles to ES5 during build time) (i.e. an ES6 port of the original version) and a version written in TypeScript (i.e. a copy of the original version). The separate versions are put in different branches of their respective Git repository.

You can download the sources from their GitHub repositories:
Note that these projects are by no means perfect samples of a very-best-practices Angular 2 project setup. Rather, my aim was to concentrate on the most important parts, keeping the setup clear and comprehensible even for Angular 2 “newbies”.

Most importantly, I have neglected:
  • Testing
  • Code validation / linting
  • Packing / minification
  • Plus potentially some other characteristics of a typical “production-ready” build
The current project setup of course also reflects the current state of my own Angular 2 knowledge. I’m still learning. I’m planning to actually develop these projects further as my knowledge grows. If you have expert knowledge in any of the associated technologies, feel free to contribute to these repositories. Note however that it’s a goal of mine to keep these projects seeds minimalistic and lean.

For now, if you want a more production-ready (however potentially more complex) Angular 2 seed, I recommend you take a look at the repositories linked in the Awesome Angular 2 repository: ES6 seeds, TypeScript seeds.

How is that useful?

I think these two projects might be of great help as you try to follow Angular 2’s official tutorials. Their main advantage over starting with the official QuickStart repository or the inofficial “Tour of heroes” repository is that you get a sound “ready to go” project setup, including an actual build server and a clean directory structure. Still, in contrast to many more advanced Angular 2 project skeletons (see above), they are very minimalistic and easily understandable with at least prior AngularJS knowledge.

You can use one of these projects as a seed to build your own clean Angular 2 project on top of. All you need to do is to delete the example business JavaScript / HTML / CSS source code to get a clean project setup.

However, if you really want to know what is going on under the hood, you should read on to find out how to set up an Angular 2 project, and how it is different from an AngularJS project setup. I highly encourage you to read on, as understanding the way Angular 2 projects work may save you from future project configuration worries.

Pages: 1 2 3

June 12, 2016

LambdaOmega V. 0.3: Even more concise Java Collections!



LambdaOmega 0.3 is now RELEASED! LambdaOmega is an open-source wrapper library around Java collections and lambdas to make them more concise and enjoyable to work with. The newest release completes collections support by adding a wrapper for Set.

Inspired by the concise collections and functions syntax of technologies like Groovy and JavaScript / lodash, LambdaOmega wraps around Java collections in order to increase ease of development, allowing you to write less code:
Map<String, Integer> map = m("a", 0).i("b", 1).i("c", 2).m;
V. 0.3 added Set support:
Set<Integer> set = set(0, 1, 2);
You can easily pipe and execute functions:
List<Integer> list2468 = l(0, 1, 2).a(3).Map(it -> it + 1).map(it -> it * 2);
Previously, V. 0.2 added a grand unified Functional Interface – use one interface instead of 29 / 12 mutually incompatible interfaces when defining a lambda function:
boolean yes = F((int it) -> it > 0).call(1);
And there’s more:
  • A more powerful yet more concise API which unifies Collection and Map access
  • Convenience classes for Integer ranges and 2D vectors
  • Functions to “convert everything into everything”
  • A drop-in replacement for the bloated, buggy CompletableFuture class.
Please feel free to visit the project’s repository on GitHub where you’ll find its exhaustive documentation. You can download its current release as a JAR file or look up the Maven dependency information.

Feedback welcome!

With Collections support being completed and thoroughly tested (>= 90%), I think the first stable release 1.0 is now quite close already. I’ll use the next release, 0.4, for small enhancement and for API cleanup.

I strongly encourage you to check out the current release and to test it out. Your feedback is highly appreciated!

If you think something important (within the scope of the project) is still lacking, or if you think some part of the API needs revision, please feel free to file an issue on the GitHub project, or comment on this article. I will gladly include your propositions into the next release before fixating the API in the first stable release.

Conclusion

I’m happy LambdaOmega is approaching its first final release. Actually, this is the first of my own open source projects to make it to the 0.3 version. (I guess creating 0.2 is easy as you’re still “in the flow”, and 0.3 really shows long-term commitment…)

Again, please check out the project on GitHub, and as always, let me know your thoughts in the comments section below. Thank you for your interest in LambdaOmega.

May 29, 2016

Project Lombok: Making Java more Groovy (part 3 of 3)


Pages: 1 2 3

Util classes

Groovy: (none)

Lombok:
@UtilityClass
public class UtilLombok {
    public String doSomething() {
        return "done!";
    }
}

UtilLombok.doSomething();
Lombok’s @UtilityClass annotation transforms a class into a typical *Util class: final, private constructor, static methods.

There is no Groovy equivalent.

Extension methods

Groovy:
class ExtensionsGroovy {
    public static String greetGroovy(String self) {
        return "Hello Groovy, this is " + self
    }
}

// In file src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule:
moduleName = lombokvsgroovy-module
moduleVersion = 1.0
extensionClasses = ch.codebulb.lombokvsgroovy.extensions.ExtensionsGroovy

// Called from Groovy code:
"World".greetGroovy() // "Hello Groovy, this is World"
Lombok:
public class ExtensionsLombok {
    public static String greetLombok(String self) {
        return "Hello Lombok, this is " + self;
    }
}

// Called from Java code:
@ExtensionMethod(ExtensionsLombok.class)
public class LombokVsGroovyTest {
 public void testExtensions() {
  "World".greetLombok() // "Hello Lombok, this is World"
 }
}
As its name suggests, Lombok’s @ExtensionMethod brings extension methods, as known e.g. from C#, to Java.

You must use @ExtensionMethod on the caller class to register your extensions.

Apart from other, more dynamic ways to extend Java classes at runtime, Groovy also provides so-called extension modules, although they come with a few caveats:
  • Even though they are compatible with @CompileStatic Groovy, hence working with the Groovy compiler, they don’t work with the Java compiler, i.e. you cannot call them from Java. It’s really the same as with e.g. the additional JDK methods which Groovy introduces: Just because you have Groovy on your class path doesn’t mean that you can call those “GDK” methods from your Java code.
  • Their sources must have been compiled in an earlier compiler run than the @CompileStatic sources which will use them. This is implicitly true for unit tests which got compiled separately from the main code; otherwise, you must compile your extension modules separately explicitly, e.g. in a separate Maven project.
  • They need explicit registration through an ExtensionModule descriptor.
Although from a design point of view, extension methods clearly are to be preferred over a collection of static *Util classes, this design choice should be carefully considered in both Lombok and Groovy: You’re still basically relying on a JVM hack which has a huge design impact on your coding style.

This is really made for if you want to design your own DSL, but I wouldn’t recommend its use for a standard enterprise project.

@Delegate

Groovy:
class DelegateGroovy {
    @Delegate
    private List<Integer> values = []
}

DelegateGroovy groovy = new DelegateGroovy();
groovy.add(1);
groovy.add(2);
groovy.add(3);
groovy.size(); // 3
Lombok:
public class DelegateLombok {
    @Delegate
    private List<Integer> values = new ArrayList<>();
}

DelegateLombok lombok = new DelegateLombok();
lombok.add(1);
lombok.add(2);
lombok.add(3);
lombok.size(); // 3
@Delegate works the same in Lombok and Groovy: Auto-delegate method calls to a field.

Note that in Groovy, the class will also be modified to implement all the interfaces of the delegate.

Most importantly, note please that this feature is in Lombok marked as “highly experimental”, and may possibly get removed in future versions.

This is yet another feature very useful for creating DSLs, but potentially long-term harmful in other scenarios.

Other common features

There is one additional annotation that both Lombok and Groovy share; we’ll not discuss its details here.
  • @Synchronized: A variant of the synchronized keyword.

Other Lombok-exclusive features

There are some additional annotations provided by Lombok without a Groovy equivalent:
  • @FieldDefaults: Set default modificators for all fields in a class.
  • @__: Meta-annotation to generate annotations while transforming the AST. “Highly experimental”!
  • @Helper: Generate method-local methods.

Other Groovy-exclusive features

Groovy does actually provide much more AST transformations than Lombok. Some of them are however for very specific purposes. The most useful ones are:
  • @InheritConstructors: Auto-inherit constructors (e.g. useful for Exception classes)
  • @AutoClone: Implement Cloneable / generate copy-constructor
  • @Sortable: Implement Comparable
These are generally very useful to implement common design patterns; it’s a pity they don’t exist in Lombok (yet).

Then of course, there’s much more to the Groovy language than just some silly AST transformations. There’s a huge amount of syntactic simplification Groovy brings, thus allowing you to write code far more concisely than Java.

Conclusion

This article really boiled down to a comparison of Lombok vs. Groovy AST transformations. Just as I have done with other topics, I created a simplified comparison table for your reference:

Feature Lombok Groovy Feature Lombok Groovy
def   X @Builder X X
@NonNull X   Unchecked exceptions X X
Getter / Setter X X @Log X  
@ToString X X @UtilityClass X  
@EqualsAndHashCode X X Extension methods X X
@TupleConstructor X X @Delegate X X
@Canonical X X @InheritConstructors   X
@Immutable X X @AutoClone   X
Immutable Setter X   @Sortable   X

Comparing those two libraries is really quite interesting. Although they have a completely different technical background, they share quite a lot of functionality and it’s nice to see that oftentimes, even the annotation names do match. Still, there are a few exclusive features to each library you’d like to see making its way into the other one.

Of course, no one would make a strict Lombok vs. Groovy assessment for a project. Rather, you would first of all ask yourself whether you can start your project on Groovy, and if not, whether you can include Lombok in your Java project. I can now honestly recommend to give it a shot.

However, this comparison also showed that it may actually make sense to combine Lombok and Groovy in a project, using Lombok’s exclusive features as a fallback for the use cases not (yet) covered by Groovy. Given the fact that combined compilation of both libraries is not an issue (as proven by the demo project), this may be a viable option to increase conciseness of a Groovy project even more.

I’ve implemented the most important comparisons covered in this article in JUnit tests which you can download from the demo project’s GitHub repository.

Please let me know whether you found this article interesting or if it lacks any information you were looking for. Feel free to share your Lombok vs. Groovy experience in the comments section as well.


Pages: 1 2 3

Project Lombok: Making Java more Groovy (part 2 of 3)


Pages: 1 2 3

@Canonical

Groovy:
@CompileStatic
@Canonical
class CanonicalGroovy {
    String name
    int age = 10
}

new CanonicalGroovy("My name", 20).equals(new CanonicalGroovy("My name", 20));
Lombok:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CanonicalLombok {
    private String name;
    private int age = 10;
}


new CanonicalLombok("My name", 20).equals(new CanonicalLombok("My name", 20)); // true
  • In Groovy, @Canonical combines @ToString, @EqualsAndHashCode and @TupleConstructor (with getter / setter generation enabled by plain Groovy already),
  • In Lombok, @Data combines @ToString, @EqualsAndHashCode, @Getter / @Setter for all fields, and @RequiredArgsConstructor.
In both cases, adding the individual annotations additionally overrides using their default values by @Canonical / @Data.

This really is just a catch-all solution to quickly build POJOs. However, at least in Groovy practice I’ve found that typically, you really want to use the individual annotations anyway for more specific code generation control. For Lombok, the use of @RequiredArgsConstructor is unfortunate because it forces you to still manually apply @AllArgsConstructor + @NoArgsConstructor if you want to replicate the Groovy behavior which seems more sensible.

Hence, unfortunately, this is almost useless in both libraries.

@Immutable

Groovy:
@Immutable
class ImmutableGroovy {
    String name
    int age = 10
}


new ImmutableGroovy();
new ImmutableGroovy("My name", 20).equals(new ImmutableGroovy("My name", 20)); // true
Lombok:
@Value
@AllArgsConstructor
public class ImmutableLombok {
    private String name;
    private int age = 10;

    public ImmutableLombok() {
        this.name = null;
    }
}

new ImmutableLombok();
new ImmutableLombok("My name").equals(new ImmutableLombok("My name"));
In Groovy, @Immutable applies @Canonical with generating getters only and creating “immutable” POJOs. In Lombok, @Value does the same with the @Data equivalent, plus all the fields become final, hence the output can derive from the Groovy version.

Immutable setters

Groovy: (none)

Lombok:
@NoArgsConstructor
@AllArgsConstructor
@Getter @Setter
@Wither
public class WitherLombok {
    private String name = "Default name";
    private int age;
}

WitherLombok lombok = new WitherLombok();
lombok.setAge(20);
WitherLombok lombok2 = lombok.withName("My name");
lombok2.getName(); // My name
lombok2.getAge(); // 20
Lombok’s @Wither generates and “immutable setter” for fields. Although this works similar to @Setter, the setter is invoked on a new object (a clone) previously constructed from calling the constructor with all the instances’ current field values. It’s hence best practice to use this in conjunction with @AllArgsConstructor.

Unfortunately, there is no Groovy equivalent.

@Builder

Groovy:
@Builder
class BuilderGroovy {
    String name
    int age
    List<String> siblings = []
}

BuilderGroovy groovy = BuilderGroovy.builder()
    .name("My name").age(20).siblings(Arrays.asList("First", "Second"))
    .build();
Lombok:
@Builder
public class BuilderLombok {
    String name;
    int age;
    @Singular
    List<String> siblings = new ArrayList<>();
}

BuilderLombok lombok = BuilderLombok.builder()
    .name("My name").age(20).sibling("First").sibling("Second")
    .build();
@Builder auto-generates the otherwise boilerplate-intense builder pattern both in Groovy and Lombok.

With the @Singular annotation, Lombok provides an enhancement to further facilitate dealing with collections. For reasons unknown, the respective feature request for Groovy has been rejected.

In case you’re searching for an equivalent to the Groovy Builder’s more concise SimpleStrategy, you’ll have to use Lombok’s combined @Accessors(fluent=true) @Getter @Setter:

Groovy:
@Builder(builderStrategy=SimpleStrategy, prefix="")
class SimpleBuilderGroovy {
    String name
    int age
    List<String> siblings = []
}

SimpleBuilderGroovy simpleGroovy = new SimpleBuilderGroovy()
    .name("My name").age(20);
Lombok:
@Accessors(fluent=true)
@Getter @Setter
public class SimpleBuilderLombok {
    String name;
    int age;
    List<String> siblings = new ArrayList<>();
}

SimpleBuilderLombok simpleLombok = new SimpleBuilderLombok()
    .name("My name").age(20);

Make exceptions unchecked

Groovy:
class ExceptionsGroovy {
    public static void tryToDoSomething() {
        doSomethingDangerous(); // no try-catch!
    }
    
    private static void doSomethingDangerous() { // no throws!
        throw new UselessException();
    }
    
    public static class UselessException extends Exception {
        
    }
}
Lombok:
public class ExceptionsLombok {
    public static void tryToDoSomething() {
        doSomethingDangerous(); // no try-catch!
    }
    
    @SneakyThrows
    private static void doSomethingDangerous() { // no throws!
        throw new UselessException();
    }
    
    public static class UselessException extends Exception {
        
    }
}
By annotating a method with @SneakyThrows, you replicate Groovy’s exception handling default behavior with Lombok, that is to make exception checking optional, even for checked exceptions.

Although in some situations, checked exceptions may be used effectively as a tool to make your business code more robust, some people will claim that the concept of checked exceptions in Java is all wrong per se (which becomes obvious when working with code which was designed without a clear idea about what checked exceptions are for), and advocate an optional-checked language design like in Groovy, Scala, or C#.

This really is a pinch by Lombok towards creating Java code which feels more “dynamically typed”. You should have a deep understanding about Java exception design, and use it sparingly even then. Note that in contrast to exceptions design with Groovy, this is a very local opt-out hook, and it can easily devolve into exception micro-management.

@Log

Groovy: (none)

Lombok:
@Log
public class LoggingLombok {
    public static void logError() {
        log.severe("An error occurred");
    }
}
In Lombok, @Log and its alternatives add a logger field which can be of any of the major Java logging frameworks classes.

Unfortunately, there is no Groovy equivalent.

Pages: 1 2 3

Project Lombok: Making Java more Groovy (part 1 of 3)



Project Lombok brings AST transformation annotations as we know and love them from Groovy to Java. Having established that it is safe for use even in “enterprise level” Java projects, I’m taking a closer look at Lombok’s capabilities in this article, comparing its features to their Groovy counterpart.

This article primarily addresses Groovy developers which are keen on applying the same level of conciseness to Java, and are interested in how to achieve that using project Lombok. I will here concentrate on the most useful and prominent Lombok and Groovy AST transformations.

In this article, Groovy code samples have a blue background color, Lombok / Java code samples have an orange one. In contrast to Lombok’s official documentation, I will also show example caller code which in my opinion best illustrates the actual code transformation.

Side note: Running Maven + Groovy + Lombok

I created a demo project showcasing the feature comparison of Lombok and Groovy as a Maven project which you can download from its GitHub repository. Based on this stackoverflow answer, I configured the Maven pom.xml such that it works well with Groovy + Lombok (in NetBeans).

def

Groovy:
class DefGroovy {
    public static def value = "Hello"
    
    public static <T> T getValue(T value) {
        def ret = value;
        return ret;
    }
}

DefGroovy.value.getClass() // String
Lombok:
public class DefLombok {
    public static <T> T getValue(T value) {
        val ret = value;
        return ret;
    }
}
Lombok’s val is a very basic version of Groovy’s def, with the following restrictions:
  • It’s only available for local variables
  • It just simply copies the type of the initialization variable. Groovy def, on the other hand, even supports changing its type at runtime.
Also, tool support for NetBeans isn’t there yet.

I dont’t see this as a very useful feature of Lombok for now.

@NonNull

Groovy: (none)

Lombok:
public class NonNullLombok {
    public static String checkNonNull(@NonNull String cannotBeNull, String canBeNull) {
        return cannotBeNull + canBeNull;
    }
}

NonNullLombok.checkNonNull(null, "World") // NullPointerException!
Lombok comes with the ability to automatically add null-checks with useful exception messages to a method for every parameter annotated with @NonNull.

Unfortunately, there is no equivalent in Groovy.

Getter / setter generation

Groovy:
class GetterSetterGroovy {
    public String name
    int age = 10
    
    protected void setName(String name) {
        this.name = name
    }
}

new GetterSetterGroovy().getAge(); // 10
new GetterSetterGroovy().setName("My name");
Lombok:
@Getter @Setter
public class GetterSetterLombok {
    @Setter(AccessLevel.PROTECTED)
    public String name;
    private int age = 10;
}

new GetterSetterLombok().getAge(); // 10
new GetterSetterLombok().setName("My name");
@Getter / @Setter are used to create property accessors which in Groovy is achieved implicitly by omitting a field’s access modificator.

Note that Lombok offers more control over getter / setter creation than Groovy. Also, you can set a getter to cache its return value by setting the respective annotation value; in Groovy, this comes close to using the @Memoized annotation on the getter.

Also, you can place @Getter / @Setter on the class to generate accessors for all fields by default, mimicking a Groovy-like behavior.

Given the central role of JavaBeans and their properties in typical enterprise projects, this is one of Lombok’s main features.

On the other hand, of course, Lombok can’t provide Groovy’s GPath property access syntactic sugar to access properties using the dot notation.

@TupleConstructor

Groovy:
@TupleConstructor
class CombinedGroovy {
    String name
    int age = 10
}

new CombinedGroovy();
new CombinedGroovy("My name", 20);
Lombok:
@NoArgsConstructor
@AllArgsConstructor
public class CombinedLombok {
    private String name;
    private int age = 10;
}

new CombinedLombok();
new CombinedLombok("My name", 20);
Whilst Groovy has the single @TupleConstructor annotation to create constructors from properties, Lombok has three, and they are based on fields:
  • @AllArgsConstructor: Closest to the Groovy equivalent. Creates a constructor by default from all the fields.
  • @RequiredArgsConstructor: Same as @AllArgs…, but by default only based on fields marked as final / @NonNull.
  • @NoArgsConstructor: Unlike Groovy, @AllArgs… overrides the default contructor unless explicitly set. Thus you can re-introduce it using this annotation.
Also note that while in Groovy, @TupleConstructor becomes a no-op if any custom constructors are present (can be overridden by setting force=true), Lombok will generate constructors regardless of whether any of them are already present or not.

This is a classic Groovy and Lombok “quick win”.

@ToString

Groovy:
@ToString(includePackage=false, includeNames=true)
class CombinedGroovy {
    String name
    int age = 10
}

new CombinedGroovy().toString() // CombinedGroovy(name:null, age:10)
Lombok:
@ToString(includeFieldNames=true)
public class CombinedLombok {
    private String name;
    private int age = 10;
}

new CombinedLombok().toString() // CombinedLombok(name=null, age=10)
In both Groovy and Lombok, @ToString generates the toString() method. In Groovy, information is taken from the class’s properties; in Lombok, it’s taken from the fields. Their output is nearly identical.

However, the Groovy equivalent offers more options. It’s the only one which supports printing the fully qualified class name (that’s even the default).

This is a very useful debugging tool in both libraries.

@EqualsAndHashCode

Groovy:
@EqualsAndHashCode(includes="name")
@TupleConstructor
class CombinedGroovy {
    String name
    int age = 10
}

new CombinedGroovy("My name", 20).equals(new CombinedGroovy("My name", 30));
Lombok:
@EqualsAndHashCode(of={"name"})
@NoArgsConstructor
@AllArgsConstructor
public class CombinedLombok {
    private String name;
    private int age = 10;
}

new CombinedLombok("My name", 20).equals(new CombinedLombok("My name", 30));
This one is similar to @ToString, and as its name suggests, this creates the equals() and hashCode() methods accordingly. Again, its name is the same for both libraries, with the Groovy version offering slightly more customization options. As with @ToString, Groovy works with properties while Lombok works with fields.

This again is an extremely useful tool to reduce boilerplate noise in production classes.

Pages: 1 2 3

May 22, 2016

Delombok: Enterprise-safe Java AST transformations



Project Lombok brings abstract syntax tree (AST) transformations to Java, allowing you to generate boilerplate code at compile time through simple annotations. With the delombok Maven plugin, this becomes a safe choice even for enterprise projects.

This blog post describes how to easily apply Java code generation for typical boilerplate tasks using Project Lombok – and how to safely introduce it to a Java project of any scale, in a non-intrusive way.

You’ll find the source code of a nicely configured (NetBeans) project in the accompanying GitHub repository.

Why should you use it?

Project Lombok allows you to use simple Java annotations to modify or extend Java source code on compile time. This is a feature well-known from Groovy projects, which comes with numerous so-called AST transformations out-of-the-box, to e.g. generate equals() / hashCode() methods, constructors, or even implement advanced features such as method-delegation. With Lombok, these features are brought to vanilla Java.

This is not about saving time when coding. That’s what static code generators (e.g. in the IDE) are for. Actual coding is done once only. Afterwards, you’ll need to be able to read your code, and to keep it up to date. This is were static code generation fails as the generated boilerplate becomes part of the source code file, and it gets in the way every time you have to revise is. Statically generated code by its very nature is potentially out-of-date as soon as it was generated. This never happens with code generated at compile time.

Code generation with Lombok

In order to use Lombok, you need to declare its Maven dependency:
<dependencies> 
 <dependency> 
  <groupId>org.projectlombok</groupId> 
  <artifactId>lombok</artifactId> 
  <version>1.14.8</version>
 </dependency>
 ...
</dependencies>
Note: At the time of writing (May 2016), this does not work with Lombok’s most recent release (1.16.8): When used in NetBeans (8.1), the IDE itself recognizes the code generated by Lombok (e.g. in autocomplete), but compilation will fail nonetheless when trying to access generated code. According to this stackoverflow answer, the current solution is a downgrade to Lombok 1.14.8.
Then you can for instance have getters and setters generated at compile time:
public class GetterSetterExample {
    @Getter @Setter
    private int age = 10;
 ...
}
and use them statically typed:
GetterSetterExample example = new GetterSetterExample();
example.getAge();

Why wouldn’t you use it?

Lombok helps you keep your Java code concise, DRY, and overall clean.

There are still viable reasons why you may be still reluctant to apply it in your project: It introduces a dependency on a third party tool, and in this case, this comes with two drawbacks:
  • A new programming style is introduced which may not be endorsed by future code maintenance personal.
  • You become dependent on a tool which may break with future Java releases.
  • (Plus, its current version indeed seems to be broken at the moment, at least when used in NetBeans.)
The second point becomes a pressing concern when you read Lombok’s backstory which clearly states that it actually relies on internal VM APIs and as such may be considered a hack:

“There is no guarantee the private APIs won't change in a later JDK and break Project Lombok.”

It does so by lack of official support for annotation processors for Java:

“If what lombok does could be done without resorting to internal API, we'd have done something else, but it can't be done, so we resort to internal API usage.”
At least, it would be favorable to have a “revert to vanilla” option with Lombok. Luckily, there is one. Enter Delombok, which is an official part of Lombok.

Safe code generation with Delombok

In order to activate Delombok, you need to add its plugin to your pom:
<plugins>
 <plugin>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok-maven-plugin</artifactId>
  <version>1.16.8.0</version>
  <executions>
   <execution>
    <phase>generate-sources</phase>
    <goals>
     <goal>delombok</goal>
    </goals>
   </execution>
  </executions>
 </plugin>
 ...
</plugins>
Note that this method supports the most recent Lombok release (even in NetBeans):
<dependencies> 
 <dependency> 
  <groupId>org.projectlombok</groupId> 
  <artifactId>lombok</artifactId> 
  <version>1.16.8</version>
 </dependency>
 ...
</dependencies>
You should then create a separate source folder to you Java files on which you want to apply Lombok AST transformations:
<resources>
    <resource>
        <directory>src/main/lombok</directory>
        <includes>
            <include> **/*.java </include>
        </includes>
    </resource>
</resources>
That way, you get a project structure like this:
  • Project
    • src
      • java: Source code to which Delombok is not applied (optional)
      • lombok: Source code to which Delombok is applied
    • target
      • generated-sources
        • lombok: Source code generated by Delombok
You’ll need to create the src/lombok folder by hand. NetBeans IDE will then automatically detect this resources directory as an additional source folder and the <plugin>’s <phase>generate-sources</phase>/<goal>delombok</goal> sub-folder as an additional “Generated Sources” folder.
Then, apply Lombok AST transformations in your src/lombok code and use it statically typed, same as above.

Note that in this case, the modified source code is indeed placed into the target/generated-sources/lombok folder.

Because the src/lombok folder is not one of Maven’s source class folders, there will be no “duplicate class” errors, whilst you’re still perfectly able to reference “delomboked” classes from “untouched” ones, and vice versa.

Of course, this configuration is not recommended for the actual development process as the additional step of generating “delomboked” source code introduces additional complexity and, more importantly, a compile time penalty. Rather, take it as your safeguard in case you’ll ever need to revoke your decision to opt for Lombok in a project: Then, delombokify your code again, and go on with manual coding. What a pity!

Before coming to a decision, you may also want to check readability of the actual code generated during a delombok run: I found that at least for the most prominent AST transformations, namely getters / setters or contructor generation, it doesn’t look at all worse than what your average IDE generates. Also not that the output of lombok’s AST transformations are highly configurable.

Conclusion

I’m a huge advocate of the strategy to generate all non-trivial code artifacts. I do believe that creating less code is better, in accordance with DRY, as long as KISS is respected. That’s part of the reason why I also like Groovy very much, and its AST transformations in particular, and that’s as well why I wholeheartedly recommend Lombok for Java projects.

Since it’s both easy and safe to apply, there’s really hardly any reason to miss this opportunity for a clean code boost.

Again, you can download the NetBeans project skeleton from its GitHub repository. Note that this project comes in two branches:
  • The delombok branch (also the HEAD revision): A demo setup for use with delombok.
  • The lombok branch: A demo setup for use with lombok.
Let me know in the comments section whether you agree with my assertions, or post what other reservations against Lombok you have found.

You may also be interested in

March 13, 2016

Groovy by example: JSON handling (part 2 of 2)


Pages: 1 2

Serializing / marshalling Java objects to JSON

Rather than building a JSON structure manually using builder invocations, it may be easier to model the structure as a Java class model and simply serialize an instance to JSON.

A similar use case is when you have an existing in-memory Java object and you want to save it to disc (you may call it a “savegame”). Here, the JSON format is a sensible choice as it is standardized, lightweight, and highly human-readable. If these factors are important in your scenario, I would recommend the JSON file format rather than, e.g. XML or some binary format.

From a Groovy implementation point of view, this is a whole different story. Groovy’s capabilities to serialize objects to JSON are there, but they are very limited.

As we just saw, we can print any object in JSON format by initializing JsonBuilder with the object:
Customer customer = new Customer("Max")
    .address(new Address("First Street", "Los Angeles"))
    .purchases([
        new Purchase(100, Date.parse("yyyy-MM-dd", "2016-03-13"))
    ])
    .discounts([(DiscountType.FIDELITY): 5])

new JsonBuilder(customer).toPrettyString();
However, the default result may be unpleasant: For instance, the date format is fixed, and time zone information is lost. There’s no straightforward way to customize JSON output from JsonBuilder. For instance, JsonBuilder will use properties rather than fields as the data source which may lead to undesired side-effects.
{
    "discounts": {
        "FIDELITY": 5
    },
    "address": {
        "street": "First Street",
        "country": null,
        "city": "City of Los Angeles" // undesired
    },
    "purchases": [
        {
            "date": "2016-03-13T00:00:00+0000", // undesired
            "price": 100
        }
    ],
    "name": "Max"
}
Yes, you could write your own solution, but why bother? There are several JSON serialization tools available for Java (and thus Groovy), and they are industry-proven and very fast. Building it yourself violates DRY design.

Here, I recommend Jackson. So far, I found it very easy to use, and it works great with generics and Groovy. But really you can use any JSON serializer of your choice. Just don’t rely on vanilla Groovy in this use case!

For Jackson: Import the maven dependency:
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.7.2</version>
</dependency>
And simply print your object structure:
ObjectMapper mapper = new ObjectMapper();

mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)

mapper.writerWithDefaultPrettyPrinter().writeValueAsString(customer)
Jackson JSON handling is easily customizable. As shown in the example, you can e.g. globally change the Date format and whether to use fields or properties (getters) for serialization (the former is typically recommended as you are literally saving the object’s internal state). For more precise control, Jackson also comes with a vast amount of annotations which you can use on your model to modify JSON (de)serialization on a per-field or per-class basis.

In the example, the output would be:
{
  "name" : "Max",
  "address" : {
    "street" : "First Street",
    "city" : "Los Angeles",
    "country" : null
  },
  "purchases" : [ {
    "price" : 100,
    "date" : "2016-03-13 00:00:00"
  } ],
  "discounts" : {
    "FIDELITY" : 5
  }
}

Deserializing / unmarshalling JSON to Java objects

You’ll typically want to have two-way serialization / deserialization of your model, i.e. “load” a saved state like this one into in-memory again:
{
    "discounts": {
        "FIDELITY": 5
    },
    "address": {
        "street": "First Street",
        "country": null,
        "city": "City of Los Angeles"
    },
    "purchases": [
        {
            "date": "2016-03-13T00:00:00+0000",
            "price": 100
        }
    ],
    "name": "Max"
}
Yes, you could use Groovy’s JsonSlurper for this:
new JsonSlurper().parseText(TEST_CUSTOMER_JSON_INPUT) as Customer
But again, this solution is far from perfect. First of all, there is again no customization. Most severely, however, Date or enum parsing is not supported and generics are not recognized:
customerJson.address.city // "City of City of Los Angeles"
customerJson.address.@city // "City of Los Angeles"
customerJson.purchases[0].class() // LazyMap
(customerJson.purchases[0] as Map).date as String // "2016-03-13T00:00:00+0000"
customerJson.discounts.keySet()[0] // "FIDELITY"
For instance, in the example where Purchase instances are held in a List<Purchase>, this becomes a List<Map> during deserialization. Because Groovy’s syntax for accessing properties of objects and keys of maps is the same, this may not matter in a truly dynamically compiled environment. But if you want to @CompileStatic, this becomes a major issue.

Thus, again I recommend using an existing JSON serialization framework like Jackson for this use case.
ObjectMapper mapper = new ObjectMapper()
Customer customerJson = mapper
    .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
    .readValue(TEST_CUSTOMER_JSON, Customer)
This really is all you need and you get full support for Date and enum parsing and generics:
customerJson.address.city // "City of Los Angeles"
customerJson.address.@city // "Los Angeles"
customerJson.purchases[0].class() // Purchase
Date.parse("yyyy-MM-dd HH:mm:ss", customerJson.purchases[0].date) // "2016-03-13 00:00:00"
customerJson.discounts.keySet()[0] // DiscountType.FIDELITY
And it works really well with Groovy.

Conclusion

Groovy comes with great out-of-the-box support for everyday JSON parsing / writing tasks. However, it clearly is not a full-fletched JSON serialization framework. Yet this isn’t a deficiency as there are excellent third-party JSON serializers available. The important part is that you realize which use cases are best implemented using vanilla Groovy, and for which ones using an external framework makes sense.

Personally, I really enjoy working with the Groovy / Jackson duo, most certainly from an ease-of-development perspective.

In the accompanying GitHub repository, you’ll find JUnit tests showcasing JSON parsing and writing with Groovy and Jackson in action.

Please let me know in the comments section whether you agree with this article or if you have a different opinion on this topic. Also let me know if I missed any important aspects of Groovy JSON handling.


Pages: 1 2