Search code examples
javajavascriptgwtmarshallingjsni

Can JSNI Marshal Enums as strings?


I'm trying to use GWT's JSNI to call a Java function through native code. The Java function has an enum in it, and I was curious to know if the enum will marshall in the way I want. I couldn't find anything useful on Google or SO, and the Google basic docs are not very specific. I'm sure I'll find out as I compile and run, but thought I might as well ask.

Given vastly simplified code like this:

package my.example.package;
public class Giant {
    public enum GiantWord { FEE, FIE, FO, FUM };
    public void sayGiantWord(GiantWord word) { /* ... */ }

    public native JavaScriptObject toJS() /*-{
        var Giant = function() {
            this.sayGiantWord = function(word) {
                [email protected]::sayGiantWord(Lmy/example/package/Giant$GiantWord;)(word);
            };
        };
        return new Giant();
    }-*/;
}

EDIT - Based on comments, let me give an alternative version of the toJS function, and avoid confusion between this and this.

    public static native JavaScriptObject toJS(final Giant g) /*-{
        var Giant = function() {
            this.sayGiantWord = function(word) {
                [email protected]::sayGiantWord(Lmy/example/package/Giant$GiantWord;)(word);
            };
        };
        return new Giant();
    }-*/;

will calling sayGiantWord("FEE") from within JavaScript (on the appropriately acquired var from toJS()) work correctly? In other words, will the JSNI marshaller properly convert a String to its matching Java enum?

I expect calling sayGiantWord(1) will be more prone to marshall correctly, since an int can be converted to an enum easily.

Other notes:

  • The GWT Eclipse plugin is what gave me the syntax for accessing the class member's enum. At least that far, GWT is working with me.
  • I don't want to pass a number, and if necessary I know I can handle the string with a conversion function in the Java class as follows; I'd just rather not do so.
public void sayGiantWordJS(String word) {
    // convert the string to an enum
    // call sayGiantWord
}

Thanks for any advice!


Solution

  • I wasn't able to get the Enum to work at all. It seems to not be supported.

    When I passed a string or a number through the JavaScript object, JSNI made no attempt to convert the input to an enum. It does convert Enums to special objects that have an "ordinal" value, but it didn't treat the number as the ordinal and didn't try to find the valueOf the input String. I considered adding a constructor to the enum, but everything I've seen says that's for adding extra data fields to the enum.

    My answer was the one I said I'd rather avoid. In the end, my code looked similar to this:

    package my.example.package;
    public class Giant {
        public enum GiantWord { FEE, FIE, FO, FUM };
        public void sayGiantWord(GiantWord word) { /* ... */ }
        public void sayGiantWordJS(String word) {
            sayGiantWord(GiantWord.valueOf(word));
        }
    
        public static native JavaScriptObject toJS(final Giant g) /*-{
            var Giant = function() {
                this.sayGiantWord = function(word) {
                    [email protected]::sayGiantWordJS(Ljava/lang/String;)(word);
                };
            };
            return new Giant();
        }-*/;
    }
    

    Note - if you pass an invalid value through sayGiantWordJS(), you will get odd behavior in that valueOf throws an exception, but doesn't do so at the point where you invoke it. In my test, I didn't see the exception until the next user interface action that I made.