Как использовать GWT-RequestFactory в Android SyncAdapter (всегда получаю ValidationTool-Error)

У меня возник вопрос об использовании GWT-RequestFactory в Android. В качестве отправной точки я использовал код из мастера «Создать связанный с AppEngine Android-проект» (информация: http://code.google.com/intl/de-DE/eclipse/docs/appengine_connected_android.html), и это сработало отлично.

Но теперь, в моем случае, я хочу расширить это приложение, чтобы использовать локальный ContentProvider с SQLite, а SyncService с SyncAdapter синхронизировать данные из ContentProvider в AppEngine с помощью RequestFactory. Теперь моя проблема заключается в следующем: я могу позвонить

MyRequestFactory requestFactory = Util.getRequestFactory(mContext, MyRequestFactory.class);

в любом действии, которое я захочу, и получу экземпляр MyRequestFactory. (Примечание: Util — это класс, созданный Мастером.) Но если я попытаюсь сделать тот же вызов из моего SyncAdapter, я получу исключение java.lang.RuntimeException: для com.hotool.client необходимо запустить RequestFactory ValidationTool. MyRequestFactory Тип RequestFactory».

Возможно, для информации: метод Util.getRequestFacory выглядит так:

/**
* Creates and returns an initialized {@link RequestFactory} of the given
* type.
 */
public static <T extends RequestFactory> T getRequestFactory(
        Context context, Class<T> factoryClass) {

    T requestFactory = RequestFactorySource.create(factoryClass);

    SharedPreferences prefs = getSharedPreferences(context);
    String authCookie = prefs.getString(Util.AUTH_COOKIE, null);

    String uriString = Util.getBaseUrl(context) + RF_METHOD;
    URI uri;
    try {
        uri = new URI(uriString);
    } catch (URISyntaxException e) {
        Log.w(TAG, "Bad URI: " + uriString, e);
        return null;
    }
    requestFactory.initialize(new SimpleEventBus(),
            new AndroidRequestTransport(uri, authCookie));

    return requestFactory;
}

Ошибка возникает в RequestFactorySource, который находится в requestfactory-client.jar. Я думаю, что это может быть проблема с загрузчиком классов, но безуспешно пытался понять это. .

Я пытался использовать ValidationTool, но, во-первых, это не помогло, а во-вторых, я обнаружил, что классы, которые будет генерировать ValidationTool, уже на месте (вероятно, благодаря обработке аннотаций, как упоминалось здесь: http://code.google.com/p/google-web-toolkit/wiki/RequestFactoryInterfaceValidation )

Кто-нибудь знает, что может быть причиной этого?

Большое спасибо и с наилучшими пожеланиями.

Маркус Нойеншвандер


person Qsi    schedule 08.11.2011    source источник
comment
Я столкнулся с той же ошибкой, я нашел что-то на how2code.wordpress.com/2011/12/02/, но это не решает проблему для меня.   -  person bembii    schedule 04.01.2012


Ответы (1)


Вы правы, Марк, это проблема с загрузчиком классов.

Это происходит в requestfactory-client.jar, здесь соответствующий источник:

class InProcessRequestFactory extends AbstractRequestFactory {

    //...

    public InProcessRequestFactory(Class<? extends RequestFactory> requestFactoryInterface) {
        this.requestFactoryInterface = requestFactoryInterface;
        deobfuscator =
            Deobfuscator.Builder.load(requestFactoryInterface,
                Thread.currentThread().getContextClassLoader()).build();
    }

    //...

}

и

public class Deobfuscator {

    //...

    public static class Builder {
        public static Builder load(Class<?> clazz, ClassLoader resolveClassesWith) {
            Throwable ex;
            try {
                Class<?> found;
                try {
                    // Used by the server
                    found = Class.forName(clazz.getName() + GENERATED_SUFFIX, false, resolveClassesWith);
                } catch (ClassNotFoundException ignored) {
                    // Used by JRE-only clients
                    found = Class.forName(clazz.getName() + GENERATED_SUFFIX_LITE, false, resolveClassesWith);
                }
                Class<? extends Builder> builderClass = found.asSubclass(Builder.class);
                Builder builder = builderClass.newInstance();
                return builder;
            } catch (ClassNotFoundException e) {
                throw new RuntimeException("The RequestFactory ValidationTool must be run for the "
                    + clazz.getCanonicalName() + " RequestFactory type");
            } catch (InstantiationException e) {
            ex = e;
        } catch (IllegalAccessException e) {
            ex = e;
        }
        throw new RuntimeException(ex);
    }

    //...

}

Проблема в том, что Thread.currentThread().getContextClassLoader(), кажется, возвращает нулевое значение при вызове из адаптера синхронизации на Android, потому что поток адаптера синхронизации создается системой, а не вашим приложением.

Я решил это, вызвав вручную вызов setContextClassLoader в методе onPerformSync перед созданием экземпляра requestfactory:

@Override
public void onPerformSync(final Account account, Bundle extras,
        String authority, final ContentProviderClient provider,
        final SyncResult syncResult) {

    Thread.currentThread().setContextClassLoader(mContext.getClassLoader());

    // ...

    MyRequestFactory requestFactory = Util.getRequestFactory(mContext,
            MyRequestFactory.class, acsidToken);

    // ...
}

Я надеюсь в этом есть смысл. Андреас

person Andreas Ka    schedule 06.01.2012
comment
Спасибо! Это решило проблему. Он заработал как раз перед тем, как вы ответили на вопрос здесь. Спасибо, в любом случае. - person Qsi; 12.01.2012
comment
Замечательный ответ. Сохраните мой проект! - person Renan Franca; 11.01.2013
comment
Восхитительный Андреас! Это решило чрезвычайно сложную проблему. - person aez; 26.01.2013
comment
@Andreas Ka, см. stackoverflow.com/questions/14522553/ Если вы можете помочь мне понять, почему ваше решение также решило этот ТАК вопрос, я также могу отметить ваш ответ как правильный! Спасибо - person aez; 26.01.2013
comment
Проблема все еще существует с библиотекой сервисов Google Play V15 (последняя на данный момент) + GWT 2.5.0. Спасибо за решение! - person OferR; 10.10.2014