tags:

views:

73

answers:

3

I created the default "hello world" GWT application and noticed that it has the following default code:

/**
 * Create a remote service proxy to talk to the server-side Greeting service.
 */
private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);

I was wondering how this is possible since the declaration of GreetingService is:

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
    String greetServer(String name) throws IllegalArgumentException;

}

I thought you weren't able to instantiate Interfaces?

Thanks!

+2  A: 

Well, for one thing, it's not calling a constructor on an interface. This is perfectly valid Java, and in many Service Locator frameworks it would be fine. It's just calling a method, which returns something implementing GreetingServiceAsync as far as the Java compiler is aware.

The next thing to remember is that it's not going to be executing as Java anyway. GWT is going to be translating all of the client code into JavaScript magically. All it's got to know is what the remote path is (so it can know where to make the relevant service calls) and what the signatures are (so the Java actually has something to work with, and so it can validate you're passing appropriate arguments to the remote service).

At execution time this isn't going to be building a Java object at all... it'll be doing something in JavaScript so that it can make the RPC... and then on the server side, you can have a real implementation of the interface listening for that request.

Jon Skeet
How does it determine the relevant implementation? I thought the "Create" call would try to instantiate whatever class you pass in?
Hortitude
@Hortitude: See my rewritten answer.
Jon Skeet
@Jon: This is true, when the application executes in compiled (JavaScript) form. But since GWT also supplies a Development Mode (which executes in Java), it must be able to create a Java object. To this end, deferred binding and Java code generators are used. You can see these generated classes, when you turn on the `-gen` compiler option.
Chris Lercher
@chris_l: Interesting to know, thanks. I think the most important point is that it simply isn't invalid Java to start with - it's important to understand the difference between trying to call a constructor on an interface, and calling a static method which will return an implementation of an interface (where you shouldn't care what the implementation is like).
Jon Skeet
+1  A: 

It's using deferred binding, and in this case with a generator to dynamically create the implementation of the interface at compile-time (or runtime in the case of DevMode, but actually it generates Java code that's compiled on-the-fly)

Thomas Broyer
+1  A: 

The RPC Plumbing Diagram mentions:

Some of these classes, such as the service proxy, are automatically generated behind the scenes and you generally will never realize they exist.

Let's take a look behind those scenes:

We'll start at /com/google/gwt/rpc/RPC.gwt.xml in gwt-user.jar:

<generate-with class="com.google.gwt.rpc.rebind.RpcServiceGenerator">
  ...
  <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService" />
  ...
</generate-with>

This specifies a deferred binding, as mentioned by Thomas Broyer. So let's go to RpcServiceGenerator:

...
return new RpcProxyCreator(remoteService);
...

Now you can take a detailed look at the relatively complex code of RpcProxyCreator and its superclass ProxyCreator. I believe, the piece of code you're looking for is in ProxyCreator.getSourceWriter:

...
composerFactory.addImplementedInterface(
  serviceAsync.getErasedType().getQualifiedSourceName());
...
Chris Lercher