Monday, January 13, 2025

Re: JsInterop consuming JS with a attributes

Interesting. As far as I know it should not have worked. Your above example should map to JavaScript:

{ getUsername: function() { .... }, getProfilePictureUrl: function() { .... } }

At the bottom of the jsinterop page there is a link to the JsInterop spec: https://docs.google.com/document/d/10fmlEYIHcyead_4R1S5wKGs1t2I7Fnp_PaNaa7XTEk0/edit

It states that you need @JsProperty in that case. GWT compiler must know if it should treat the interface method as method or as property.

-- J.

Craig Mitchell schrieb am Montag, 13. Januar 2025 um 23:02:07 UTC+1:
Thanks again Thomas,

Yep, getters worked.  I thought I tried this previously, but obviously not.

I didn't need the JsProperty annotation. maybe because the interface is marked as native:

@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public interface CrazyGamesUser {
  String getUsername();
  String getProfilePictureUrl();
}

I'll update https://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJsInterop.html to mention this is how you access attributes using JsInterop.

Cheers.

On Tuesday, 14 January 2025 at 4:19:36 am UTC+11 Thomas Broyer wrote:
On Monday, January 13, 2025 at 10:14:33 AM UTC+1 ma...@craig-mitchell.com wrote:
Hi Thomas,

Can an interface have attributes?  I thought interfaces can only have methods?

Yes, you'd have to make them getters (probably need to annotate them with @JsProperty too)
 
So if I make it:

@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public interface CrazyGamesUser {
}

I can't see how I can add the attributes:

public String username;
public String profilePictureUrl;

?

Thanks again.

On Monday, 13 January 2025 at 7:03:43 pm UTC+11 Thomas Broyer wrote:
Use an interface rather than a class.


Rule of thumb is: use a class only if it maps to a "constructor" in JS, i.e. something you'll either create an instance of, or use in an "instanceof" check; for everything else (generally something you get from another API or "receive" in a callback), use an interface.

In this case, I think you could also use name="Object".

On Monday, January 13, 2025 at 7:47:28 AM UTC+1 ma...@craig-mitchell.com wrote:
Overlay types do work, and make it a little better:

public class CrazyGamesUser extends JavaScriptObject {
  protected CrazyGamesUser() {}
  public final native String getUserName() /*-{ return this.username; }-*/;
  public final native String getProfilePictureUrl() /*-{ return this.profilePictureUrl; }-*/;
}

However, it would be great if JsInterop just worked, so I could just do:

@JsType(isNative = true, namespace = JsPackage.GLOBAL)
public static class CrazyGamesUser {
  public String username;
  public String profilePictureUrl;
}

Maybe I'm missing something?
On Monday, 13 January 2025 at 4:02:40 pm UTC+11 Craig Mitchell wrote:
I'm calling some existing JS that returns a JS Object which I've implemented in JsInterop:

@JsType(isNative = true, namespace = "window.CrazyGames.SDK")
public static class JsUser {
    public native Promise<CrazyGamesUser> getUser();
}

I can happily call it:
sdk.user.getUser()
  .then(user -> {
    // Do something with the user
    return null;
  })
  .catch_(error -> {
    return null;
  });

This issue is I'm struggling to work out how to define the return object "CrazyGamesUser".  The actual JS object is just this:
{
    "username": "SingingCheese.TLNU",
    "profilePictureUrl": "https://images.crazygames.com/userportal/avatars/4.png"
}

If I define it like this:

@JsType(isNative = true, namespace = JsPackage.GLOBAL)
public static class CrazyGamesUser {
  public String username;
  public String profilePictureUrl;
}

I get a java.lang.ClassCastException.

So if I set the name to "?":

@JsType(isNative = true, name = "?", namespace = JsPackage.GLOBAL)
public static class CrazyGamesUser {
  public String username;
  public String profilePictureUrl;
}

Then I get a compile error:
'?' can only be used as a name for native interfaces in the global namespace.

But if I make it an interface, I can't have the member variables.

If I do remove the member variables, it does work, and I can access them via some JSNI:

public static native String getUsername(CrazyGamesUser instance) /*-{
  return instance.username;
}-*/;

But that's really ugly.  What's the correct approach here?

Thanks.

--
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 view this discussion visit https://groups.google.com/d/msgid/google-web-toolkit/b0909a0e-46c5-4717-87c8-15eef025bbb3n%40googlegroups.com.

No comments:

Post a Comment