GWT.create()是GWT中的反射等价物, 但它只需要类文字,而不是Class类的完全限定String。 如何使用GWT.create()动态创建带有字符串的类?
根据许多GWT论坛帖子不可能,但是如何在Rocket-GWT(http://code.google.com/p/rocket-gwt/wiki/Ioc)和Gwittir(http://code.google.com/p/gwittir/wiki/Introspection)等框架中完成
答案 0 :(得分:13)
尽管很棘手,但这是可能的。以下是血腥的细节:
如果你只把GWT视为JS的直接Java,它就行不通。但是,如果您在编译期间考虑使用GWT编译器Compiles and Executes的Generators - Special类,则可以。因此,您可以在编译时生成java源代码。
我今天有这样的需求 - 我们的系统处理服务的动态资源,结束为字符串和类的需要。这是我提出的解决方案 - 顺便说一句,它在托管,IE和Firefox下工作。
一些注意事项:
我希望尽快发布源代码。交叉你的手指。 :)
答案 1 :(得分:5)
布赖恩,
问题是GWT.create不知道如何为你的抽象类选择正确的实现
我遇到了与新的GWT MVP编码风格类似的问题 (见GWT MVP documentation)
当我打电话时:
ClientFactory clientFactory = GWT.create(ClientFactory.class);
我得到了同样的错误:
延迟绑定结果类型'com.test.mywebapp.client.ClientFactory'不应该是抽象的
我所要做的就是将以下行添加到MyWebapp.gwt.xml文件中:
<!-- Use ClientFactoryImpl by default -->
<replace-with class="com.test.mywebapp.client.ClientFactoryImpl">
<when-type-is class="com.test.mywebapp.client.ClientFactory"/>
</replace-with>
然后它就像一个魅力
答案 2 :(得分:5)
我今天遇到了这个并找到了解决方案。提问者基本上想要编写一个方法,例如:
public <T extends MyInterface> T create(Class<T> clz) {
return (T)GWT.create(clz);
}
这里MyInterface只是一个标记接口,用于定义我希望能够动态生成的类的范围。如果您尝试编写上述代码,则会出现错误。诀窍是定义一个“实例化器”,例如:
public interface Instantiator {
public <T extends MyInterface> T create(Class<T> clz);
}
现在定义一个返回上述实例的GWT延迟绑定生成器。在生成器中,查询TypeOracle以获取所有类型的MyInterface并为它们生成实现,就像对任何其他类型一样:
e.g:
public class InstantiatorGenerator extends Generator {
public String generate(...) {
TypeOracle typeOracle = context.getTypeOracle();
JClassType myTYpe= typeOracle.findType(MyInterface.class.getName());
JClassType[] types = typeOracle.getTypes();
List<JClassType> myInterfaceTypes = Collections.createArrayList();
// Collect all my interface types.
for (JClassType type : types) {
if (type.isInterface() != null && type.isAssignableTo(myType)
&& type.equals(myType) == false) {
myInterfaceTypes.add(type);
}
for (JClassType nestedType : type.getNestedTypes()) {
if (nestedType.isInterface() != null && nestedType.isAssignableTo(myType)
&& nestedType.equals(myTYpe) == false) {
myInterfaceTypes.add(nestedType);
}
}
}
for (JClassType jClassType : myInterfaceTypes) {
MyInterfaceGenerator generator = new MyInterfaceGenerator();
generator.generate(logger, context, jClassType.getQualifiedSourceName());
}
}
// Other instantiator generation code for if () else if () .. constructs as
// explained below.
}
MyIntefaceGenerator类就像任何其他延迟绑定生成器一样。除非您直接在上述生成器中调用它,而不是通过GWT.create。一旦完成MyInterface的所有已知子类型的生成(在生成器中生成MyInterface的子类型时,请确保使类名具有唯一的模式,例如MyInterface.class.getName()+“_ MySpecialImpl”) ,只需通过迭代MyInterface的所有已知子类型并创建一堆
来创建Instantiatorif (clz.getName().equals(MySpecialDerivativeOfMyInterface)) { return (T) new MySpecialDerivativeOfMyInterface_MySpecialImpl();}
代码风格。最后抛出异常,以便在所有情况下都可以返回一个值。
现在,您要拨打GWT.create(clz);
,而不是执行以下操作:
private static final Instantiator instantiator = GWT.create(Instantiator.class);
...
return instantiator.create(clz);
另请注意,在GWT模块xml中,您只需为Instantiator定义一个生成器,而不是为MyInterface生成器定义:
<generate-with class="package.rebind.InstantiatorGenerator">
<when-type-assignable class="package.impl.Instantiator" />
</generate-with>
宾果!
答案 3 :(得分:4)
究竟是什么问题 - 我猜你希望除了类文字之外还要将参数传递给生成器。
您可能已经知道传递给GWT.create()的类文字主要是一个选择器,以便GWT可以选择并执行一个最终吐出类的生成器。将参数传递给生成器的简单方法是在接口中使用注释并将interface.class传递给GWT.create()。注意,接口/类必须扩展传递给GWT.create()的类文字。
class Selector{
}
@Annotation("string parameter...")
class WithParameter extends Selector{}
Selector instance = GWT.create( WithParameter.class )
答案 4 :(得分:2)
一切皆有可能......尽管可能很困难甚至无用。正如Jan提到的那样,你应该使用发电机来做到这一点。基本上你可以创建你的接口生成器代码,它接受该接口并在创建时编译并返回实例。一个例子可能是:
//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");
您需要知道的是如何做发电机。我可能会告诉你,最后你在生成器中做的是以这种方式创建Java代码:
if ("clase1".equals(className)) return new clase1();
else if ("clase2".equals(className)) return new clase2();
...
在决赛中我想,常见的是我可以在InstanceFactory中手工完成这个... 最诚挚的问候
答案 5 :(得分:2)
我能够做我认为你正在尝试做的事情,它正在加载一个类并动态地将它绑定到一个事件;我使用Generator来动态地将类链接到事件。我不推荐它,但这是一个例子,如果它有帮助:
http://francisshanahan.com/index.php/2010/a-simple-gwt-generator-example/
答案 6 :(得分:1)
没看过rocket / gwittir的代码(如果你想知道他们是怎么做的,你应该怎么做,毕竟它是开源的),我只能猜测他们采用延迟绑定这样的方式在编译期间,它们计算出所有对反射的调用,并静态生成实现这些调用所需的所有代码。所以在运行期间,你不能做不同的。
答案 7 :(得分:1)
在GWT中你无法做到的事情。
虽然GWT在编译时很好地模拟了Java,但运行时当然是完全不同的。大多数反射都不受支持,并且无法在运行时生成或动态加载类。
我简要介绍了Gwittir的代码,我认为他们在编译时正在做“反思”。这里:http://code.google.com/p/gwittir/source/browse/trunk/gwittir-core/src/main/java/com/totsp/gwittir/rebind/beans/IntrospectorGenerator.java
答案 8 :(得分:1)
您可以通过在服务器端执行此操作来避免整个问题。说服务 witch接受String并返回某种可序列化的超类型。 在服务器端,你可以做
return (MySerializableType)Class.forName("className").newInstance();
根据您的具体情况,它可能不是一个很大的性能瓶颈。