tags:

views:

8712

answers:

7

GWT.create() is the reflection equivalent in GWT, But it take only class literals, not fully qualified String for the Class name. How do i dynamically create classes with Strings using GWT.create()?

Its not possible according to many GWT forum posts but how is it being done in frameworks like Rocket-GWT (http://code.google.com/p/rocket-gwt/wiki/Ioc) and Gwittir (http://code.google.com/p/gwittir/wiki/Introspection)

A: 

Not having looked through the code of rocket/gwittir (which you ought to do if you want to find out how they did it, it is opensource after all), i can only guess that they employ deferred binding in such a way that during compile time, they work out all calls to reflection, and statically generate all the code required to implement those call. So during run-time, you cant do different ones.

Chii
A: 

What exactly is the question - i am guessing you wish to pass parameters in addition to the class literal to a generator.

As you probably already know the class literal passed to GWT.create() is mostly a selector so that GWT can pick and execute a generator which in the end spits out a class. The easist way to pass a parameter to the generator is to use annotations in an interface and pass the interface.class to GWT.create(). Note of course the interface/class must extend the class literal passed into GWT.create().

class Selector{

}

@Annotation("string parameter...")
class WithParameter extends Selector{}

Selector instance = GWT.create( WithParameter.class )
mP
A: 

What you're trying to do is not possible in GWT.

While GWT does a good job of emulating Java at compile time the runtime is of course completely different. Most reflection is unsupported and it is not possible to generate or dynamically load classes at runtime.

I had a brief look into code for Gwittir and I think they are doing their "reflection stuff" at compile time. Here: http://code.google.com/p/gwittir/source/browse/trunk/gwittir-core/src/main/java/com/totsp/gwittir/rebind/beans/IntrospectorGenerator.java

Jon Tirsen
It is possible - The BeanModel from GXT does actually that - Wrapping code around generated code at compile time.
aldrinleal
A: 

Everything is possible..although may be difficult or even useless. As Jan has mentioned you should use a generator to do that. Basically you can create your interface the generator code which takes that interface and compile at creation time and gives you back the instance. An example could be:

//A marker interface
public interface Instantiable {
}
//What you will put in GWT.create
public interface ReflectionService {
 public Instantiable newInstance(String className);
}
//gwt.xml, basically when GWT.create finds reflectionservice, use reflection generator
<generate-with class="...ReflectionGenerator" >
<when-type-assignable class="...ReflectionService" />
</generate-with>  
//In not a client package
public class ReflectionGenerator extends Generator{
...
}
//A class you may instantiate
public class foo implements Instantiable{
}
//And in this way
ReflectionService service = GWT.create(ReflectionService.class);
service.newInstance("foo");

All you need to know is how to do the generator. I may tell you that at the end what you do in the generator is to create Java code in this fashion:

if ("clase1".equals(className)) return new clase1();
else if ("clase2".equals(className)) return new clase2();
...

At the final I thought, common I can do that by hand in a kind of InstanceFactory... Best Regards

A: 

Hi Miguel,

I'm trying to do exactly what you have described in your above post. I have implemented the code but I get an error by having ReleflectionService as result type

Deferred binding result type 'com.im.gen.client.ReflectionService' should not be abstract

Where should I implement this interface ReflectionService so that I can provide an implementation for the newInstance method? Also, I'm slightly confused about your last snippet of code. Here you are returning the concrete instance of a class based on the String passed in. Does this exist in your ReflectionGenerator class? Any class that extends Generator must implement a generate() method that returns a String, so I'm curious as to how all this fits together. Perhaps you might be able to fill in the blanks for me?

Thanks in advance,

Brian

Brian Boyle
+2  A: 

It is possible, albeit tricky. Here are the gory details:

If you only think as GWT as a straight Java to JS, it would not work. However, if you consider Generators - Special classes with your GWT compiler Compiles and Executes during compilation, it is possible. Thus, you can generate java source while even compiling.

I had this need today - Our system deals with Dynamic resources off a Service, ending into a String and a need for a class. Here is the solutuion I've came up with - btw, it works under hosted, IE and Firefox.

  • Create a GWT Module declaring:
    • A source path
    • A Generator (which should be kept OUTSIDE the package of the GWT Module source path)
    • An interface replacement (it will inject the Generated class instead of the interface)
  • Inside that package, create a Marker interface (i call that Constructable). The Generator will lookup for that Marker
  • Create a base abstract class to hold that factory. I do this in order to ease on the generated source code
  • Declare that module inheriting on your Application.gwt.xml

Some notes:

  • Key to understanding is around the concept of generators;
  • In order to ease, the Abstract base class came in handy.
  • Also, understand that there is name mandling into the generated .js source and even the generated Java source
  • Remember the Generator outputs java files
  • GWT.create needs some reference to the .class file. Your generator output might do that, as long as it is referenced somehow from your application (check Application.gwt.xml inherits your module, which also replaces an interface with the generator your Application.gwt.xml declares)
  • Wrap the GWT.create call inside a factory method/singleton, and also under GWT.isClient()
  • It is a very good idea to also wrap your code-class-loading-calls around a GWT.runAsync, as it might need to trigger a module load. This is VERY important.

I hope to post the source code soon. Cross your fingers. :)

aldrinleal
A: 

I was able to do what I think you're trying to do which is load a class and bind it to an event dynamically; I used a Generator to dynamically link the class to the event. I don't recommend it but here's an example if it helps:

http://francisshanahan.com/index.php/2010/a-simple-gwt-generator-example/

Francis Shanahan