null

NullPointerException, probably…

On Using the Right Tool for the Job

leave a comment »

Disclaimer: The code samples in the post below are for brain teasing only. Do not, I repeat, do not ever do such things for any other purpose!

A friend of mine is a big fan of puzzlers. Any puzzlers, including programming ones. Here’s his latest and greatest:

Write some code in the static initializer to make the assert pass:

public class Test {
 static {
//Write some code here
 }

public static void main(String[] args) {
 Integer a = 20;
 Integer b = 20;
 assert (a + b == 60);
 }
}

Don’t forget to enable assertions if you want to solve this one (-ea as VM parameter).

If you solved it, or don’t feel like puzzlers, read on for the solution and the punchline.

First, the solution: You need to know refection and two facts about Integers to solve this one:

  1. Integers have cache for all values in range -128 to 127.
  2. Integers use that cache during auto-boxing (as opposite to using Integer’s constructor, for example).

Well, you also need to know the exact implementation of the Integer class to figure out where the cache is and what’s the name, but rt.jar sources are here for the rescue. Guess what? the cache is a private variable inside a private inner class. Joy-joy.

Here’s the plan:

  1. Get Integer’s class object.
  2. Get the list of its inner classes.
  3. Find the right one (what a relief, it only has one. Or not – it is subject to change in future versions since we are digging in highly encapsulated stuff . Duh.)
  4. Get the cache field from it.
  5. It’s private, set it to accessible in order to get the value of the field.
  6. Change the value of “20” to be “30”

Here’s the code of the static initializer:

 static {
try {
 Class<?>[] declaredClasses = Integer.class.getDeclaredClasses();
 Field cacheField = declaredClasses[0].getDeclaredField("cache");
 cacheField.setAccessible(true);
 ((Integer[]) cacheField.get(null))[20 + 128] = 30;
 } catch (Exception e) { e.printStackTrace(); }
 }

Personally, I hate it. It’s ugly, it messes with very low-level encapuslated stuff that one even doesn’t suppose to know, and it is fragile (e.g. it won’t work if Integer is created with constructor).

And fairly, we just got lucky. If Integers did not have the cache then we would not  have any way to change what “+” does!

So, why this simple trick is so difficult to impossible to implement? Simple – Java is not intended for those tricks. Java is static, and it is good! It means that you can rely on it. 20+20 will (almost always) be 40. That is Good.

If you want to do dynamic stuff, like changing the behavior of  a “+” operator, you’d better use the right tool for the job. E.g. – Groovy.

Here’s the Groovy version of the puzzler:

//Write some code here
Integer a = 20
Integer b = 20
assert 60 == a + b

Looks almost the same (without the main() mess, some ridiculous semicolons and the need to include -ea in VM parameters), but the difference in the way to achieve the desired is huge. Since Groovy is dynamic it is intended to do stuff like changing the behavior of the plus sign. Here’s the facts about Groovy that you need to know to solve this one:

  1. Groovy operates with wrappers, always.
  2. Groovy implements operators though methods. “+” is implemented in plus() method.
  3. Using Groovy’s MetaClasses you can easily replace method with any closure.

Here’s the plan:

  1. Get Integer’s MetaClass.
  2. Replace plus() method with implementation that returns 60.

That’s all. Really. Here’s the code:

Integer.metaClass.plus = {int i -> 60 }

Nuff said. Now you only have 2 options. Stop doing those ugly tricks, or at least do it with the right tools for the job.

Written by JBaruch

21/05/2012 at 16:57

Posted in Development

Tagged with , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: