GWT Динамическая загрузка с использованием GWT.create () с литералами String вместо литералов Class - PullRequest
15 голосов
/ 16 января 2009

GWT.create () - эквивалент отражения в GWT, Но для этого нужны только литералы класса, а не полностью определенная строка для имени класса. Как мне динамически создавать классы со строками, используя GWT.create ()?

Это невозможно по многим постам на форуме GWT, но как это делается в таких фреймворках, как Rocket-GWT (http://code.google.com/p/rocket-gwt/wiki/Ioc) и Gwittir (http://code.google.com/p/gwittir/wiki/Introspection)

)

Ответы [ 9 ]

13 голосов
/ 25 февраля 2010

Это возможно, хотя и сложно. Вот кровавые детали:

Если вы думаете, что GWT только как прямая Java для JS, это не сработает. Однако, если вы рассматриваете Генераторы - Специальные классы с вашим компилятором GWT, который компилируется и выполняется во время компиляции, это возможно. Таким образом, вы можете генерировать исходный код Java даже при компиляции.

У меня была эта потребность сегодня - наша система работает с динамическими ресурсами вне службы, заканчивая строкой и потребностью в классе. Вот решение, которое я придумал - кстати, он работает под управлением hosted, IE и Firefox.

  • Создайте модуль GWT, объявив:
    • Исходный путь
    • Генератор (который должен храниться ВНЕ пакет с исходным путем модуля GWT)
    • Замена интерфейса (вместо интерфейса создается класс Generated)
  • Внутри этого пакета создайте интерфейс Marker (я называю это Constructable). Генератор будет искать этот маркер
  • Создайте базовый абстрактный класс для хранения этой фабрики. Я делаю это для того, чтобы облегчить сгенерированный исходный код
  • Объявите, что модуль наследуется в вашем Application.gwt.xml

Некоторые заметки:

  • Ключ к пониманию заключается в концепции генераторов;
  • Для удобства базовый класс Abstract пригодился.
  • Кроме того, следует понимать, что в сгенерированном источнике .js существует обязательное именование и даже сгенерированный источник Java
  • Помните, что Генератор выводит файлы Java
  • GWT.create нужна ссылка на файл .class. Выходные данные вашего генератора могут это делать, если на них ссылаются как-то из вашего приложения (проверьте, что Application.gwt.xml наследует ваш модуль, который также заменяет интерфейс генератором, объявленным вашим Application.gwt.xml)
  • Обернуть вызов GWT.create внутри фабричного метода / синглтона, а также в GWT.isClient ()
  • Очень хорошая идея также обернуть ваши вызовы загрузки классов кода вокруг GWT.runAsync, так как это может потребовать запуска загрузки модуля. Это ОЧЕНЬ важно.

Я надеюсь выложить исходный код в ближайшее время. Скрестить пальцы. :)

5 голосов
/ 13 декабря 2011

Я столкнулся с этим сегодня и нашел решение. Спрашивающий, по сути, хочет написать метод, такой как:

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 и сгенерируйте реализации для них так же, как и для любого другого типа:

например:

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") просто создайте Instantiator, повторив все известные подтипы MyInterface и создав группу

if (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);

Также обратите внимание, что в вашем XML-модуле GWT вы будете определять генератор только для Instantiator, а не для генераторов MyInterface:

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

Бинго!

5 голосов
/ 14 ноября 2010

Brian

Проблема в том, что GWT.create не знает, как подобрать правильную реализацию для вашего абстрактного класса

У меня была похожая проблема с новым стилем кодирования GWT MVP (см. документацию 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>

Тогда это работает как шарм

4 голосов
/ 31 января 2009

В чем именно вопрос - я предполагаю, что вы хотите передать параметры в дополнение к литералу класса в генератор.

Как вы, наверное, уже знаете, литерал класса, передаваемый в GWT.create (), в основном является селектором, так что GWT может выбирать и выполнять генератор, который в конце концов выплевывает класс. Самый простой способ передать параметр генератору - использовать аннотации в интерфейсе и передать interface.class в GWT.create (). Обратите внимание, что интерфейс / класс должен расширять литерал класса, передаваемый в GWT.create ().

class Selector{
}

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

Selector instance = GWT.create( WithParameter.class )
2 голосов
/ 10 апреля 2010

Я смог сделать то, что, я думаю, вы пытаетесь сделать, это загрузить класс и динамически привязать его к событию; Я использовал Генератор, чтобы динамически связать класс с событием. Я не рекомендую это, но вот пример, если это помогает:

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

2 голосов
/ 08 сентября 2009

Все возможно ... хотя может быть трудным или даже бесполезным. Как упоминал Ян, вы должны использовать генератор для этого. По сути, вы можете создать свой интерфейс генераторный код, который принимает этот интерфейс и компилируется во время создания и возвращает вам экземпляр. Примером может быть:

//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 ... С наилучшими пожеланиями

1 голос
/ 27 октября 2011

Вы можете избежать всей проблемы, выполнив ее на стороне сервера. Скажи с услугой witch берет String и возвращает какой-то сериализуемый супер тип. На стороне сервера вы можете сделать

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

В зависимости от ваших обстоятельств, это может не быть узким местом с большой производительностью.

1 голос
/ 18 июня 2009

То, что вы пытаетесь сделать, невозможно в 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

1 голос
/ 18 января 2009

Не просмотрев код rocket / gwittir (что вам следует сделать, если вы хотите узнать, как они это сделали, в конце концов, это open source), я могу только догадываться, что они используют отложенное связывание таким образом что во время компиляции они обрабатывают все вызовы для отражения и статически генерируют весь код, необходимый для реализации этих вызовов. Поэтому во время выполнения вы не можете делать разные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...