Hi all,

I encountered some odd behaviour of GWT's compiler regarding generic
interfaces and abstract implementations. I had compiled
JavaScript-code failing with
   "com.google.gwt.core.client.JavaScriptException: (TypeError):
foo.set is not a function"

It took a while to hunt the problem down. This mail is to warn you
about the found issue and to provide a workaround. Maybe the
developers find this worth to be fixed?

In short, suppose you had the following interface and its implementation:

        interface Foo<T> {
                T get();
                void set( T v );
        }

        abstract class AbstractFoo {
                String v;
                public String get() { return v; }
                public void set(String v) { this.v = v; }
        }

        class MyFoo extends AbstractFoo implements Foo<String> {}


Then, the following code will fail in web mode:

                Foo<String> foo = new MyFoo();
                foo.set( "bar" ); // FAILS

foo.set(...) will fail with
"com.google.gwt.core.client.JavaScriptException: (TypeError): foo.set
is not a function". But *only in web* mode though - in hosted mode the
code runs fine.

I was able to figure out the problematic scenario:
- you have a generic interface
- you have an abstract implementing the interface's methods WITHOUT
implementing the interface itself (no "implements" statement)
- you have a concret class extending the abstract one. this class now
features an "implements" statement to implement the generic interface

This scenario might seem slightly constructed, but in my project we
had code looking just like that. The Java-Compiler didn't complain,
neither did GWT's compiler. So the code is valid Java.

To circumvent this error, the following does work:

        abstract class AbstractFoo  implements Foo<String>  {
                String v;
                public String get() { return v; }
                public void set(String v) { this.v = v; }
        }
        class MyFoo extends AbstractFoo{}

Essentially, you move the "implements" statement from the concret to
the abstract class. This looks more logical anyways, one might think.
But remember: both ways are valid in Java.


Attached you'll find a full GWTTestCase, which documents the issue.

Regards,
Stefan


package client;
import com.google.gwt.junit.client.GWTTestCase;


public class InterfaceImplementationTest extends GWTTestCase {
        
        @Override
        public String getModuleName() {
                return "Test";
        }
        
        /**
         * Simple Interface
         *
         */
        interface Bar {
                String get();
                void set( String v );
        }
        
        public void testWillSucceed /* both in hosted and web mode */ () {
                
                abstract class AbstractBar {
                        String v;
                        public String get() { return v; }
                        public void set(String v) { this.v = v; }
                }
                class MyBar extends AbstractBar implements Bar {}
                
                Bar bar = new MyBar();
                bar.set( "foo" );
                assertEquals( "foo", bar.get() );
        }
        
        /**
         * Generic Interface
         *
         * @param <T>
         */
        interface Foo<T> {
                T get();
                void set( T v );
        }
        
        public void testWillFailInWebMode /* but will succeed in hosted mode */ 
() {
                
                abstract class AbstractFoo {
                        String v;
                        public String get() { return v; }
                        public void set(String v) { this.v = v; }
                }
                class MyFoo extends AbstractFoo implements Foo<String> {}
                
                // This will work OK...
                MyFoo myfoo = new MyFoo();
                assertNull( myfoo.get() );
                myfoo.set( "bar" ); // this won't fail
                assertEquals( "bar", myfoo.get() );
                
                // ...but this won't!
                Foo<String> foo = new MyFoo();
                assertNull( foo.get() );
                foo.set( "bar" ); // FAILS with
"com.google.gwt.core.client.JavaScriptException: (TypeError): foo.set
is not a function"
                assertEquals( "bar", foo.get() );
        }
}

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/Google-Web-Toolkit?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to