Cómo utilizar GWT-RequestFactory en Android SyncAdapter (siempre aparece ValidationTool-Error)

Tengo una pregunta sobre el uso de GWT-RequestFactory en Android. Como punto de partida, utilicé el código del asistente "Crear un proyecto de Android conectado a AppEngine" (información: http://code.google.com/intl/de-DE/eclipse/docs/appengine_connected_android.html) y funcionó muy bien.

Pero ahora, en mi caso, quiero extender esta aplicación para usar un ContentProvider local con SQLite y un SyncService con SyncAdapter sincronizar los datos del ContentProvider al AppEngine usando RequestFactory. Ahora mi problema es el siguiente: puedo llamar

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

en cualquier actividad que desee y recibiré una instancia de MyRequestFactory. (Nota: Util es una clase creada por el Asistente). Pero si intento hacer la misma llamada desde mi SyncAdapter, obtendré una java.lang.RuntimeException: la RequestFactory ValidationTool debe ejecutarse para com.hotool.client. MyRequestFactory tipo RequestFactory ”.

Tal vez para su información: el método Util.getRequestFacory se ve así:

/**
* 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;
}

El error ocurre en RequestFactorySource que se encuentra en el requestfactory-client.jar Creo que esto puede ser un problema de Class-Loader, pero traté de resolverlo sin éxito.

Traté de usar ValidationTool pero, en primer lugar, no ayudó y, en segundo lugar, descubrí que las clases que generará ValidationTool ya están en su lugar (probablemente gracias al procesamiento de anotaciones como se menciona aquí: http://code.google.com/p/google-web-toolkit/wiki/RequestFactoryInterfaceValidation)

¿Alguien tiene una idea de qué podría causar esto?

Muchas gracias y un saludo.

Markus Neuenschwander

preguntado el 08 de noviembre de 11 a las 10:11

Me encuentro con el mismo error, encontré algo en how2code.wordpress.com/2011/12/02/…, pero eso no me resuelve el problema. -

1 Respuestas

Tienes razón Mark, este es un problema de cargador de clases.

Ocurre en requestfactory-client.jar, aquí la fuente relevante:

class InProcessRequestFactory extends AbstractRequestFactory {

    //...

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

    //...

}

y

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);
    }

    //...

}

El problema es que Thread.currentThread (). GetContextClassLoader () parece devolver un valor nulo cuando se llama desde el adaptador de sincronización en Android, porque el hilo del adaptador de sincronización lo crea el sistema, no su aplicación.

Resolví esto llamando manualmente a setContextClassLoader en el método onPerformSync antes de crear una instancia de 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);

    // ...
}

Espero que esto tenga sentido. Andreas

Respondido el 06 de enero de 12 a las 16:01

¡Gracias! Eso resolvió el problema. Lo ejecuté justo antes de responder la pregunta aquí. Gracias de cualquier manera. - Qsi

Respuesta maravillosa. ¡Guarda mi proyecto! - Renan Franca

¡Andreas asombroso! Esto solucionó un problema extremadamente difícil. - aez

@Andreas Ka, ver stackoverflow.com/questions/14522553/… Si puede ayudarme a entender por qué su solución también resolvió esa pregunta SO, ¡puedo marcar su respuesta como correcta allí también! Gracias - aez

El problema persiste con la biblioteca de servicios de Google Play V15 (la última en este momento) + GWT 2.5.0. ¡Gracias por brindar una solución! - OferR

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.