Tuesday, August 29, 2017

Re: Weird behavior from JsInterop for uninitialized fields/attributes.

makes sens. 

I have noticed that if it is explicitly set to null then it will be set to null in Js as well, once again it gets translated to Js :)  

Thanks for the clear cut explanation!

Le mardi 29 août 2017 13:16:45 UTC+2, Thomas Broyer a écrit :

On Tuesday, August 29, 2017 at 12:36:11 PM UTC+2, zakaria amine wrote:

This is a minor remark, and it does affect the functioning of JsInterop, as far as I experienced, but may be worth looking into by GWT folks. I have the following Js object that I am wrapping in Java:

var Hotel = function() {
this.guests = [];

Hotel.prototype = {
: function(guest) {
: function(){
return this.guests.length;

@JsType(isNative=true, namespace=GLOBAL)
public class Hotel {
public native final int getGuestCount();
public native final void addGuest(Guest guest);

I pass a Guest object to the addGuest Method

@JsType(isNative=true, namespace=GLOBAL, name="Object")
public class Guest {
public int guestId;

public String firstName;

public String lastName;
public String roomNumber;

public class Test implements EntryPoint {

String uninitializedString;
public void onModuleLoad() {

Hotel hotel = new Hotel();

Guest guest = new Guest();
.firstName= "test";
//passed object is guest = {firstName: "test"}

Guest guest2 = new Guest();
.firstName = "test";
.lastName = uninitializedString;
//passed object is guest = {firstName: "test", lastName: undefined}, should also be guest = {firstName: "test"}


In short, if you are assigning an uninitialized variable to an uninitialized Object field, the field will not be ignored anymore by JsInterop, and will be transpiled as undefined, although it is still uninitialized. This happens often with the builder pattern.

Let's translate your code to JS manually:

let uninitializedString;

function onModuleLoad() {
  let hotel = new Hotel();

  let guest = new Object(); // because you used name="Object"; at that point, guest is {}
  guest.firstName = "test";

  let guest2 = new Object();
  guest2.firstName = "test";
  guest2.lastName = unitializedString;

See? your property assignments are creating the properties on a bare JS Object, and assigning 'undefined' will still create the property.

Also keep in mind that what you declare in your native types are only mapping about how to use/call the JS API, not necessarily what it actually is under the hood; i.e. just because you use a field does not mean that it's actually a "simple" JS property: it could have been defined with a setter, so guest2.lastName=undefined might actually have a side-effect other than creating a property (that's exactly that kind of property that's declared when you use getter/setter methods for a @JsProperty in a non-native type); and conversely, you could use getter/setter methods for a @JsProperty in a native type, that's a "simple" property in JS.

BTW, the 'undefined' here is seen by GWT as a Java 'null', but it won't bother initializing the field with 'null' as it treats 'undefined' and 'null' as equivalent (to a Java 'null'); this is an optimization technique (saves a few bytes in generated payload, and CPU cycles at runtime) that IIRC was added at some point in the GWT 2 lifecycle; earlier versions would explicitly initialize the uninitializedString field to null in the Test constructor/initializer.

You received this message because you are subscribed to the Google Groups "GWT Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit+unsubscribe@googlegroups.com.
To post to this group, send email to google-web-toolkit@googlegroups.com.
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.

No comments:

Post a Comment