Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserving nullability contracts in runtime #422

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Preserving nullability contracts in runtime #422

wants to merge 2 commits into from

Conversation

denis-zhdanov
Copy link

Thus PR does two things:

  • configures the build to generate null-checks based on NonNull method parameters/return values annotations
  • removes explicit null-checks

The above is achieved by the Traute javac plugin - it enhances compilation in a way to insert target checks into generated bytecode.

Let's consider RxMenuItem.actionViewEvents():

Source code

@CheckResult @NonNull
public static Observable<MenuItemActionViewEvent> actionViewEvents(@NonNull MenuItem menuItem) {
  return new MenuItemActionViewEventObservable(menuItem, Functions.PREDICATE_ALWAYS_TRUE);
}

Resulting bytecode looks like if it's compiled from the source below:

@CheckResult @NonNull
public static Observable<MenuItemActionViewEvent> actionViewEvents(@NonNull MenuItem menuItem) {
  if (munuItem == null) {
    throw new NullPointerException("menuItem == null");
  }
  Observable<MenuItemActionViewEvent> tmpTrauteVar1 = new MenuItemActionViewEventObservable(menuItem, Functions.PREDICATE_ALWAYS_TRUE);
  if (tmpTrauteVar1 == null) {
    throw new NullPointerException("Detected an attempt to return null from a method com.jakewharton.rxbinding2.view.RxMenuItem.actionViewEvents() marked by @android.support.annotation.NonNull");
  }
}

Bytecode

javap -c ./rxbinding/build/intermediates/classes/release/com/jakewharton/rxbinding2/view/RxMenuItem.class
...
  public static io.reactivex.Observable<com.jakewharton.rxbinding2.view.MenuItemActionViewEvent> actionViewEvents(android.view.MenuItem);
    Code:
       0: aload_0
       1: ifnonnull     14
       4: new           #1                  // class java/lang/NullPointerException
       7: dup
       8: ldc           #2                  // String menuItem == null
      10: invokespecial #3                  // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
      13: athrow
      14: new           #9                  // class com/jakewharton/rxbinding2/view/MenuItemActionViewEventObservable
      17: dup
      18: aload_0
      19: getstatic     #5                  // Field com/jakewharton/rxbinding2/internal/Functions.PREDICATE_ALWAYS_TRUE:Lio/reactivex/functions/Predicate;
      22: invokespecial #10                 // Method com/jakewharton/rxbinding2/view/MenuItemActionViewEventObservable."<init>":(Landroid/view/MenuItem;Lio/reactivex/functions/Predicate;)V
      25: astore_1
      26: aload_1
      27: ifnonnull     40
      30: new           #1                  // class java/lang/NullPointerException
      33: dup
      34: ldc           #11                 // String Detected an attempt to return null from a method com.jakewharton.rxbinding2.view.RxMenuItem.actionViewEvents() marked by @android.support.annotation.NonNull
      36: invokespecial #3                  // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
      39: athrow
      40: aload_1
      41: areturn

Please note that Traute is configured in the same way as the explicit checks:

  • it throws NullPointerException from failed checks (default behavior)
  • error message pattern is PARAMETER_NAME == null

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant