days
-1
-1
hours
-1
-7
minutes
0
-9
seconds
-2
-3
search
Maintain type-safety

Type-safe reflection code with @Jailbreak

Scott McKinney
manifold
© Shutterstock /Martins Vanags

Do you struggle when using reflection code? In itself, reflection code is not type-safe, which can cause problems down the road. There must be a better alternative! You can maintain type-safety with @Jailbreak from the Manifold project and rest assured that your code is efficient.

Ever overexpose fields and methods just so they can be accessed from tests? Ever write reflection code in order to access private class members?

You can stop doing that now. Maintain integrity and type-safety with @Jailbreak from the Manifold project.

@Jailbreak MyWidget widget = new MyWidget();
String value = widget.privateField; // type-safely access private fields and methods

The problem with reflection

We’re not supposed to use reflection in order to access or modify otherwise inaccessible class members, right? Well, that depends on the alternatives. There are situations where reflection is the lesser of two evils or the difference between winning customers and losing them. The fact is, reflection is an indispensable JVM feature we all benefit from.

But if you still feel uneasy about using it, that’s a good sign! Reflection code is nasty stuff primarily because it totally escapes type-safety.

Let’s say you need brand information from MyWidget:

public class MyWidget implements Widget {
  private String brand;
  ...
}

Since brand is private and MyWidget is not your class to modify, you must resort to reflection:

SEE ALSO: REST API Vision with Manifold

MyWidget myWidget = (MyWidget) widget;
...
Field field = MyWidget.class.getDeclaredField("brand");
field.setAccessible(true);
String brand = (String) field.getValue(myWidget);

Its use of Strings and casting make reflection difficult to read and error-prone to write. Even worse, it escapes type-safety. The compiler can neither verify your access to the brand field nor its String type. If MyWidget 2.0 changes any of this, your build will not detect the break. Thus the real trouble with reflection code is that it is statically unverifiable.

@Jailbreak

Given the difficulty of reading and writing reflection code and its lack of type-safety, there should be a better way.

Why not provide a language construct in order to declare the intent of subverting encapsulation and then leverage the compiler’s strengths to verify your code. This is precisely what the @Jailbreak annotation achieves:

@Jailbreak MyWidget myWidget = (MyWidget) widget;
...
String brand = myWidget.brand;

As you can see @Jailbreak lets you access otherwise inaccessible members of MyWidgetfrom the myWidget variable.

@Jailbreak mitigates the issues with reflection. Use it to leverage the convenience and type-safety of the Java compiler and let Manifold generate reliable, efficient reflection code for you.

Basic use

This is an example of basic usage:

@Jailbreak Foo foo = new Foo(1);
foo.privateMethod();
foo.privateMethod("hey");
foo._privateField = 88;
public class Foo {
  private final int _privateField;
  
  public Foo(int value) {
    _privateField = value;
  }
  
  private String privateMethod() {
    return "hi";
  }
  
  private String privateMethod(String param) {
    return param;
  }
}

Using the jailbreak() extension

Similar to @Jailbreak you can call the jailbreak() extension method from any expression in order to gain type-safe access to private fields, methods, and types.

SEE ALSO: Manifold: Alien technology

Foo foo = new Foo();
foo.jailbreak().privateMethodOnFoo();

This method is especially handy when you have a chain of member access expressions and you want to use them concisely.

something.foo().jailbreak().bar.jailbreak().baz = value;
Note: reflection code is also horribly inefficient if not properly cached and accessed. Manifold fixes all that too.

IntelliJ IDEA

Use @Jailbreak with the Manifold plugin for IntelliJ IDEA. The plugin provides comprehensive support for @Jailbreak including code completion, navigation, usage searching, etc.

Visit the Manifold project on GitHub to learn more.

Looking for more info about Manifold? Refer to our two-part series by Scott McKinney covering innovative language features for Java.

Part 1: Manifold: The reinvention of code generators

Part 2: Manifold: Extension methods for Java

Author
Scott McKinney
Scott McKinney is the founder and principle engineer at Manifold Systems. Previously, he was a staff engineer at Guidewire where he designed and created Gosu. He currently pounds code by the truckload while listening to way too much retro synthwave.

Leave a Reply

Be the First to Comment!

avatar
400
  Subscribe  
Notify of