GWT动态加载使用GWT.create()和字符串文本而不是类文本

GWT动态加载使用GWT.create()和字符串文本而不是类文本,gwt,Gwt,create()是GWT中的反射等价物, 但它只接受类文本,而不是类名的完全限定字符串。 如何使用GWT.create()动态创建带有字符串的类 根据许多GWT论坛的帖子,这是不可能的,但是在Rocket GWT()和Gwittir()这样的框架中是如何做到的呢?没有仔细阅读Rocket/Gwittir的代码(如果你想知道他们是如何做到的,你应该这样做,毕竟它是开源的),我只能猜测,它们采用延迟绑定的方式是,在编译时,它们完成对反射的所有调用,并静态生成实现这些调用所需的所有代码。因此,在运行时

create()是GWT中的反射等价物, 但它只接受类文本,而不是类名的完全限定字符串。 如何使用GWT.create()动态创建带有字符串的类


根据许多GWT论坛的帖子,这是不可能的,但是在Rocket GWT()和Gwittir()这样的框架中是如何做到的呢?

没有仔细阅读Rocket/Gwittir的代码(如果你想知道他们是如何做到的,你应该这样做,毕竟它是开源的),我只能猜测,它们采用延迟绑定的方式是,在编译时,它们完成对反射的所有调用,并静态生成实现这些调用所需的所有代码。因此,在运行时,您不能执行不同的操作。

问题到底是什么?我猜您希望将类文本之外的参数传递给生成器

您可能已经知道,传递给GWT.create()的类文本主要是一个选择器,这样GWT就可以选择并执行一个生成器,最终生成一个类。将参数传递给生成器的最简单方法是在接口中使用注释,并将interface.class传递给GWT.create()。当然,请注意,接口/类必须扩展传递到GWT.create()中的类文本


在GWT中,您试图做的是不可能的

虽然GWT在编译时很好地模拟了Java,但运行时当然完全不同。大多数反射都不受支持,并且不可能在运行时生成或动态加载类


我对Gwittir的代码进行了简要的研究,我认为他们在编译时做了“反射”工作。这里:

一切皆有可能……尽管可能很难,甚至毫无用处。正如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");
最后我想,我可以在InstanceFactory中手动完成这项工作。。。
致以最诚挚的问候

这是可能的,尽管有点棘手。以下是血淋淋的细节:

如果您只将GWT看作是直接的Java到JS,那么它将不起作用。但是,如果您认为Gnter——特殊类与GWT编译器在编译期间编译并执行,则是可能的。因此,您甚至可以在编译时生成java源代码

我今天有这样的需求——我们的系统处理服务之外的动态资源,以字符串结尾,需要一个类。这是我提出的解决方案-顺便说一句,它在托管IE和Firefox下工作

  • 创建一个GWT模块,声明:
    • 源路径
    • 发电机(应保持在GWT模块源路径包之外)
    • 接口替换(它将注入生成的类而不是接口)
  • 在该包中,创建一个标记接口(我称之为可构造的)。生成器将查找该标记
  • 创建一个基本抽象类来保存该工厂。我这样做是为了简化生成的源代码
  • 声明在Application.gwt.xml上继承该模块
一些注意事项:

  • 理解的关键是围绕发电机的概念
  • 为了方便起见,抽象基类派上了用场
  • 另外,要理解生成的.js源代码甚至生成的Java源代码中都存在名称强制
  • 记住生成器输出java文件
  • GWT.create需要一些对.class文件的引用。您的生成器输出可能会这样做,只要它是从您的应用程序中以某种方式引用的(检查application.gwt.xml是否继承了您的模块,这也会用application.gwt.xml声明的生成器替换接口)
  • 将GWT.create调用包装在工厂方法/singleton中,也包装在GWT.isClient()下
  • 还可以围绕GWT.runAsync包装代码类加载调用,因为它可能需要触发模块加载。这是非常重要的

我希望尽快发布源代码。祝你好运

我能够做我认为您正在尝试做的事情,即加载一个类并将其动态绑定到一个事件;我使用生成器将类动态链接到事件。我不推荐它,但这里有一个例子,如果它有帮助的话:

布莱恩

问题是GWT.create不知道如何为抽象类选择正确的实现

我对新的GWT MVP编码风格也有类似的问题 (见附件)

当我打电话时:

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>


然后它就像一个符咒一样工作

您可以通过在服务器端这样做来避免整个问题。带着服务说 witch接受字符串并返回某种可序列化的超类型。 在服务器端,您可以执行以下操作

return (MySerializableType)Class.forName("className").newInstance();

根据您的情况,这可能不是一个很大的性能瓶颈。

我今天遇到了这个问题,并找到了一个解决方案。提问者基本上想要写一个方法,例如:

public <T extends MyInterface> T create(Class<T> clz) {
    return (T)GWT.create(clz);
}
代码的样式。最后抛出一个异常,以便在所有情况下都返回一个值

现在调用
GWT.create(clz)改为执行以下操作:

private static final Instantiator instantiator = GWT.create(Instantiator.class);
...
return instantiator.create(clz);
还要注意,在GWT模块xml中,您将只为实例化器定义生成器,而不是为MyInterface生成器定义生成器:

<generate-with class="package.rebind.InstantiatorGenerator">
    <when-type-assignable   class="package.impl.Instantiator" />
</generate-with>


宾果

GXT中的BeanModel实际上可以在编译时围绕生成的代码包装代码,但这仍然需要ClientFact
public interface Instantiator {
    public <T extends MyInterface> T create(Class<T> clz);
}
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.
}
if (clz.getName().equals(MySpecialDerivativeOfMyInterface)) { return (T) new MySpecialDerivativeOfMyInterface_MySpecialImpl();}
private static final Instantiator instantiator = GWT.create(Instantiator.class);
...
return instantiator.create(clz);
<generate-with class="package.rebind.InstantiatorGenerator">
    <when-type-assignable   class="package.impl.Instantiator" />
</generate-with>