Prototype that covers ARM, auto-generating boilerplate, even SneakyThrows, AND it works in eclipse.
Reinier Zwitserloot
reinier at zwitserloot.com
Tue Jul 28 17:36:58 PDT 2009
Hey guys,
Well, 'prototype' isn't entirely correct: Because of the glacial pace
of java updates, Project Lombok (the 'prototype') is meant as a real
world java plugin, to be used anywhere, including production
environments. Still, it's one way to get more familiar with some of
the coin proposals, most notably ARM, as its still on the shortlist.
Unlike any other prototype, this one works seamlessly in current
eclipse and javac distributions, without requiring modifying any of
those files. In my opinion, eclipse (or any other IDE) support is
_crucial_ - prototypes without IDE support won't give you a real feel
for a feature, as nobody (sane) programs java without the help of a
smart editor. The few souls that program without the help of auto-
completion, error checking as you type, and easy navigation around
your codebase, has jumped ship to python or ruby a loooong time ago.
It's a long story, so maybe you'd rather just watch the less-than-4-
minute screencast than read on: http://projectlombok.org/
What's in there right now:
ARM: It's not quite like Josh's proposal, as Project Lombok works on
the existing parser architecture. Here's some sample code. Yes, that's
an annotation being used as a language feature. Sue me. It works, it's
namespaced, and it's one click away from helpful javadoc, and, Neal,
you'll like this: It's in a library!
void copy(String from, String to) throws IOException {
@Cleanup InputStream in = new FileInputStream(from);
@Cleanup OutputStream out = new FileOutputStream(to);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
It works by replacing all statements BELOW a @Cleanup annotated local
variable declaration, all the way up to the end of that scope, with a
try statement that runs those statements in the try block, and as a
finally block, calls a method named "close" with no arguments on the
variable. You can also pick another method to call, by specifying it
as a parameter, like so:
@Cleanup("dispose") CoolBar someSwtWidget = new CoolBar();
Note that it does NOT attempt to 'hide' exceptions from the close
method if the try body also throws an exception, simply because you
just can't get there with syntax sugar. We'd like to, though.
Elimination of vast tracts of boilerplate:
@Getter will generate a getter. @Setter will generate a setter (on
fields). @EqualsAndHashCode will generate an equals and hashCode
implementation using all non-static, non-transient fields, and is
smart enough to use Arrays.deepHashCode where neccessary, for example.
@ToString generates a toString, and if you want all of those at once,
"@Data" bundles all of that: equals, hashCode, toString, getters for
all fields, setters for all non-final fields, and you also get a
constructor that initializes all final fields. Example:
@Data public class Point {
private final int x, y;
}
What would you rather read (let alone type)? The above 3 lines, or the
more than 70 lines that it would take to do it 'right', currently? I
know Joe took this kind of boilerplate busting off the table for
project coin, but working with Project Lombok on my own source code,
@Data is pure heaven.
SneakyThrows:
Yes, I know this entire list hated the idea, but it's our project.
@SneakyThrows is just like throws, except you don't have to catch or
'throw onward' the exceptions when you call a method with @SneakyThrows.
Example:
@SneakyThrows(UnsupportedEncodingException.class)
public static String fromUTF8(byte[] b) {
//return new String(b, Charset.forName("UTF-8")) WOULD work, but
doesn't work on java 5 VMs.
return new String(b, "UTF-8");
}
new Thread(new Runnable() {
@SneakyThrows
public void run() {
//run() should have thrown Throwable, but, backwards
compatibility means that'll never ever get fixed.
//with @SneakyThrows, that's not a problem any longer.
throw new Throwable();
}
});
The last one: @Synchronized.
The actual 'synchronized' keyword on a method will lock on either
'this' or on the class object, depending on whether the method is
static. This is nice in some cases, but more often you want to lock on
a private field. There's even a java puzzler on the topic. With
@Synchronized, a private field named $lock is generated, and the
entire method body is guarded by that lock instead. Also works with
static methods (static $LOCK is generated), and you can specify your
own lock (though in that case, you'll have to write the field
yourself) as well.
The current set of transformations are all triggered by annotations,
but this isn't required, and Project Lombok can be extended with your
own transformations, which could for example trigger on a special
method call. Could be useful for writing your own prototypes.
As you'll see in the video, the eclipse integration goes MUCH further
than ordinary annotation processors: The moment you finish typing the
'r' on a @Getter annotation, the getter _immediately_ appears in your
outline view. "Find declaration" will even jump to the annotation that
generated the method!
The javac integration is nice as well: You just need to put lombok.jar
in the classpath as you compile. That's it - no need to change javac
or download a prototype compiler at all. Just:
javac -cp lombok.jar *.java
Only requirement: It has to be javac v1.6. -target 1.5 works just
fine, though, and when using lombok with eclipse, you can use eclipse
3.4 or 3.5, and run eclipse on java5 or java6.
So, don't wait for java 7 to be released, and start enjoying the
benefits of ARM and getting rid of your boilerplate right now - http://projectlombok.org/
--Reinier Zwitserloot and Roel Spilker
More information about the coin-dev
mailing list