Skip to content

Ensure Java null isn't exposed to jsinterop as undefined #10331

@niloc132

Description

@niloc132

GWT normalizes away JS null vs undefined so that Java code doesn't need to worry about the difference. There are two cases (that I can think of right now) where Java code can deal explicitly with undefined:

  • Js.undefined() gives Java the ability to ensure it has an undefined value, though it will show up as null in any Java == comparisons
  • Js.typeof(value) will return "undefined" when passed an undefined value (whereas null would result in "object"). The exception to this rule is document.all, due to a bug in IE that ended up being made into the spec.

To achieve this, Cast.maskUndefined is used in cases where the Java == or != operators could be used on a nullable reference.

static native Object maskUndefined(Object src) /*-{
return (src == null) ? null : src;
}-*/;

That is, if the compiler can't prove that one side or the other cannot be a null, it will replace the <reference> with maskUndefined(<reference>).

This means that when jsinterop returns an undefined into Java code (either as a property value, param to a method, return value from a method, etc), Java doesn't mind which, and can detect undefined (via value == null && Js.typeof(value).equals("undefined")). However, Java code that assigns properties, calls methods, or returns values to JS cannot guarantee that it is actually returning nulls vs undefineds - that is the topic of this issue.

This can be irritating for a few issues in JS - for example, === is usually the preferred comparison between objects in JS, yet while null === null and null == null both evaluate to true, null == undefined is true while null === undefined is false.

I propose that we add a configuration property (or compiler flag) to apply maskUndefined to any values as they are passed to native jsinterop. This will result in a small size increase in some cases, so probably should be opt-in.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions