yolpos

@yolpogists

A blooming good Java toString for the rest of us

Have you ever System-d dot out an Object and got its class name @ its hexadecimal hashcode?

Chances are: it wasn’t what you were hoping for and it didn’t you help much.

The problem is that, in Java, we lack a function which generates a good and consistent textual representation for any Java object.

If we had it, we would write:

System.out.println( toString.apply(myObject) ); 

instead of

System.out.println( myObject.toString() ); // finger crossed, we 
// have a good toString.

We would then stop cursing at developers for not implementing a damn good toString.

Hacking a universal toString is easy, if you decide to ignore a few edge cases.

It just requires you to use the reflection API to iterate over all the object’s fields to print them.

I wrote one that you can use with Nashorn jjs, with nudge4j and in any Java 8 program.

It’s written as a Nashorn JavaScript function. The function pretty much delegates all of the work to the poorly named ReflectionToStringBuilder (part of Apache Commons Lang).

You don’t need Apache Commons Lang in your classpath (I don’t have it either). I hate dependencies and I am not going to ask you to add it just for this. The code comes with a good trick to load it on demand from the maven repo.

How do we use the toString function ?

In Nashorn jjs and nudge4j you load it and you are ready to go:

load("https://gist.githubusercontent.com/lorenzoongithub/d1a7e047b29aef79d363b3b56c2e666a/raw/c486452e25d0f419101ae7bddd259240b17f1762/toString.js")
toString(java.lang.Thread.currentThread());

In Java you need to write a bit of boiler plate to wrap it up as a Java Function:

Function<Object, String> toString = new Function<Object,String>() {
private ScriptEngine engine;

{
try {
engine = new ScriptEngineManager().
getEngineByName("JavaScript");
try (InputStream is = new URL("https://gist.githubusercontent.com/lorenzoongithub/d1a7e047b29aef79d363b3b56c2e666a/raw/c486452e25d0f419101ae7bddd259240b17f1762/toString.js").openStream()) {
        engine.eval(new InputStreamReader(
is, StandardCharsets.UTF_8));
}
} catch (ScriptException | IOException e) {
throw new RuntimeException(e);
}
}
  public String apply(Object oj) {
try {
return ""+
((Invocable)engine).invokeFunction("toString", oj);
} catch (NoSuchMethodException | ScriptException e) {
throw new RuntimeException(e);
}
}
};
System.out.println(toString.apply(Thread.currentThread()));

And that’s it: a universal function to stringify any Java Object.

It won’t have an impact on your day to day work but it might turn handy on one of those debugging days.

Debug less.

loading toString.js in nudge4j

More by yolpos

Topics of interest

More Related Stories