We have been using this technique for more than a year and it works
perfectly. We call it "Java Notation Object", hehe and you should
understand the limitations, which more or less you are currently
fulfilling. Just a few changes...
The most important, yes, you should use
@JsType(isNative=true,namespace=GLOBAL,name="Object"), so you are actually
ignoring any kind of typing, so this is more a "scheme" of where to find
things than an actual typed object. This is pretty important! This is
pretty similar to JSON but in Java, and these classes are not actually Java
classes, are just a scheme. All these limitations are the common
intersection of the feature between Java and JS.
You can do some tricks to use collections but we end up removing all of
them and using arrays instead. But, to make it easy to work with, we added
some @JsOverlay to return or set the Collection. For example if you have
"String[] roles" you can add "@JsOverlay getRoleSet() { return
Stream.of(roles).collecto(toSet()); }". Overlays are ok bc there are just
like extension method or static method, so no behavior is added to the
object.
This work perfectly on both sides, but there is a small annoying
difference between GWT and Java, in java new Foo() will initialize
primitive types and in GWT (js) will not. So we never use constructor
directly, in the kind of classes we always add a static factory method and
we initialize any non-nullable field, even primitives! So in java you are
actually creating the object of the specified type, but in JS you are just
calling "new Object()", but it is ok, bc where are using a scheme, no a
type. And we never use instanceof on these schemes! This will work on the
Java side, but I strongly discourage, you should not need to do that.
Finally, we never use getter and setter, don't make sense, you "cannot use
inheritance" (you can use with some ticks too, for example using some int
or string field as the type indicator and using, for example, the visitor
pattern to traverse, this is what actually people need to do in JS so, no
magic just the common intersection of features between java and json),
almost everything is like final and you must not add behavior, so it is
much explicit and easier to just make all field public.
I think the first you should do is removing getters and setters, and add
@JsType(native,Object) to all your types, this refactor can be done almost
instantly in your IDE (inline method). Then stop using Collection might not
be so easy to refactor. So you might continue using it either using
overlays or creating a custom jsinterop-compatible type. In this case, I
recommend to not to use the whole java.util API bc it will force you to
export the whole API and use generateJsInteropExports. If you are really
interested or need help there just ask, but just try out avoiding maps, and
using arrays. Anyways, the "Map/List own interface" should work too, just
neet to make it work.
On Fri, Sep 29, 2017 at 12:53 PM Thomas Broyer <[email protected]> wrote:
>
>
> On Friday, September 29, 2017 at 11:09:42 AM UTC+2, Jürgen Beringer wrote:
>>
>> Hey,
>>
>> currently I tried the 2. time to move our application from gwt 2.7 to
>> gwt 2.8, but I have big problems with the changes of JsInterop.
>>
>> The application contains a serverside java part, running in a jetty and
>> the client part, build with gwt, so I can reuse many software on server and
>> client side. (It is the main part of the website www.spreadshirt.com )
>> To use also the same data classes (containing only fields with getter and
>> setter, no other methods) on both sides, I used JsInterop and it works very
>> well with gwt 2.7 and exchanged the data as json.
>>
>> Example Data class:
>>
>> @JsType
>> public class MyObject {
>> private String id;
>>
>> @JsProperty
>> public String getId() {
>> return id;
>> }
>> @JsProperty
>> public void setId(String id) {
>> this.id = id;
>> }
>> }
>>
>>
>> The class can be used on server side like any normal java class with any
>> REST Framework. On gwt side I was able to convert a transmitted json to the
>> class with:
>>
>>
>> MyObject myObject = getJsTypeObject(JsonUtils.safeEval(jsonString));
>> //use getter and setter to access fields
>>
>> public static native <T> T getJsTypeObject(JavaScriptObject result)/*-{
>> return result;
>> }-*/;
>>
>>
>> And to create Objects on gwt side and send them to the server as json:
>>
>> MyObject myObject = new MyObject();
>> myObject.setId("1");
>> String jsonString = stringify(myObject);
>>
>>
>> public static final native String stringify(Object result) /*-{
>> return JSON.stringify(result);
>> }-*/;
>>
>>
>> I also solved the problem of List and Map with an own Interface, which is
>> an ArrayList/HashMap on serverside and an own implemented native List/Map
>> on gwt side.
>>
>> The application has more than 100 such Objects which are heavily used on
>> server and client side in many methods which are also be used on both
>> sides. So implementing them twice for server and client side would be a big
>> overhead.
>> Now is my question, how can I convert this gwt 2.7 code to gwt 2.8
>> (mainly to be able to use Java8 syntax in future). I tried multiple
>> variants, but it seems for me, JsInterop in gwt 2.8 is not planned for such
>> usecases which were possible in gwt 2.7 withou any problems.
>> I can either use a native Javascript Object in gwt (native=true) or a in
>> GWT created Object in Javascript. But I see no solution to do both with the
>> same Type.
>>
>> I get 2 Problems
>>
>> - Casting issues: I can't use native=true because I also want to
>> create such Objects on gwt side, so on every assignment (jsonString to
>> typed variable) I get a cast exception and at least in superdev mode I
>> can't deactivate the cast exceptions
>>
>> If you never do "instanceof" (or expect cast exceptions) on client-side,
> you could probably use isNative=true,namespace=GLOBAL,name="Object"; that
> way, all your objects are plain old JS objects (no specific
> class/constructor is generated in JS), which is actually exactly what you'd
> expect from JSON.parse().
>
>>
>> - field name problems: The jsonString of the last example is
>> {"id_g_$3":"1"} and not {"id":"1"} because the JsProperty for getter and
>> setter works only fine with native objects. If I add JsProperty to the
>> field itself, I can't do have JsProperty for the getter and setter, so I
>> have to add JsIgnore to them. But then when I work with native Objects I
>> can't use the getter and setter on gwt side. I would need JsProperty on
>> getter, setter and the field itself, but this is also not allowed.
>>
>>
> The "id_g_$3" is probably because you don't -generateJsInteropExports;
> contrary to 2.7, in 2.8, the "don't obfuscate @JsProperty/@JsMethod names"
> only applies when you -generateJsInteropExports.
> But if you switch to isNative=true,namespace=GLOBAL,name="Object", you
> don't even need it.
>
> --
> 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 [email protected].
> To post to this group, send email to [email protected].
> Visit this group at https://groups.google.com/group/google-web-toolkit.
> For more options, visit https://groups.google.com/d/optout.
>
--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/google-web-toolkit.
For more options, visit https://groups.google.com/d/optout.