¿Cómo puedo mantener GWT de tratar de incluir todas las clases serializable cuando uso ArrayList

StackOverflow https://stackoverflow.com/questions/2210226

  •  18-09-2019
  •  | 
  •  

Pregunta

Tengo un servicio RPC en GWT que necesita para devolver una lista. La lista puede ser llenado con diversos tipos de objetos, todos los cuales son serializable y todos están referenciados en cualquier lugar mi servicio por lo que deben estar a disposición de GWT RPC. Sin embargo, a menos que me puse un parámetro de tipo genérico (por ejemplo ArrayList<String>), GWT me da la advertencia:

Return type: java.util.ArrayList
    java.util.ArrayList
      Verifying instantiability
         java.util.ArrayList
            [WARN] Checking all subtypes of Object which qualify for serialization`
Adding '465' new generated units

En esencia, sólo quiero una forma de declarar Lista o ArrayList sin GWT tratando de generar código para cada objeto serializable en la ruta de clase. ¿No hay alguna manera de saber GWT que sé lo que estoy haciendo y no volverse loco?

¿Fue útil?

Solución

Permítanme ampliar lo que dijo David Nouls. El compilador GWT no puede leer su mente, así que cuando usted no puede especificar lo que pueden ser los tipos de retorno, GWT asume que puede ser cualquier cosa, y tiene que hacer trabajo extra para asegurarse de que puede suceder en el lado del cliente Javascript.

Usted realmente debe especificar qué tipos son capaces de ser devueltos. No es bueno sólo para hacer esto -. Como el compilador producirá un código más optimizado, en lugar de generar código para manejar '465 unidades genreated', por lo que sus descargas serán más rápidos

Yo sugeriría la creación de una interfaz vacío llamado "BaseResult" y luego tener los objetos que devolver todos los que implemente esa interfaz.

/**
 * Marker interface 
 */
public interface BaseResult {
}

A continuación, se especifica que el tipo de retorno de su método de RPC es ArrayList:

public interface MyRpcService extends RemoteService {
  public ArrayList<BaseResult> doRpc();
}

A continuación, comprobar que su declaración todos los objetos de poner en práctica esa interfaz.

public class UserInfo implements BaseResult {}
public class Order implements BaseResult {}

Ahora el compilador GWT tendrá un tiempo mucho más fácil la optimización de su código.

Otros consejos

Es menos deseable tener los serializadores tipo GWT compilador de construcción para todo bajo el sol; en el peor de los casos, se produce un error en su totalidad, ya que, por ejemplo, no puede haber una clase (de digamos una biblioteca GWT de terceros que está utilizando) que declara un tipo en el paquete de "cliente" que implementa java.io.Serializable . En caso de intento de usar que teclee el código, se convierte en parte de la ruta de clases que analiza el compilador GWT para construir un serializador tipo para; Sin embargo, en el tiempo de ejecución la clase no es parte de la ruta de clase en el servidor porque el tipo se definió en el paquete de "cliente" y por lo tanto no compilados para el servidor! llamadas RPC, si se intentan utilizar ese tipo específico o no, error con una excepción ClassNotFound. Perfecto!

También es, como el cartel articulado, imposible hacer existentes tipos primitivos implementar alguna de las interfaces marcador ya sea IsSerializable o una interfaz de marcador personalizado (como BaseResult como se sugirió anteriormente).

Sin embargo, se necesita una solución! Así que aquí es lo que ocurrió: 1) Uso IsSerializable (o alguna subclase de ella) en lugar de utilizar java.io.Serializable en todos sus objetos de transferencia personalizados.

2) Utilice la siguiente implementación de RpcObject en aquellos casos donde se necesita un tipo de objeto genérico para contener un valor que sabe que ser serializable GWT-RPC (ya se trate de uno de sus objetos de transferencia personalizada que implementa IsSerializable o una mayor tipo de "primitivo", como java.lang.String [ver los comentarios en la implementación RpcObject por debajo de esos tipos que se han lista blanca] GWT que ya sabe cómo serializar!)

Esta solución está funcionando para mí ... que tanto mantiene GWT de construcción-tipo serializadores para cada clase java.io.Serializable bajo el sol, mientras que al mismo tiempo me permite que el desarrollador para transferir valores de alrededor de usar un único / tipo uniforme de los primitivos (que no puedo añadir la interfaz de marcador IsSerializable a), así como mis propias transferencia IsSerializable objetos. He aquí un ejemplo del uso de RpcObject (aunque el uso es tan simple, me siento un poco extraño sobre la inclusión de tales ejemplos):

RpcObject rpcObject = new RpcObject();
rpcObject.setValue("This is a test string");

Gracias a la java-genéricos engaño del método getValue (), de fundición se pueden mantener al mínimo, por lo que para recuperar el valor (ya sea en el cliente o el servidor), que sólo puede hacer lo siguiente sin ningún la necesidad de un reparto:

String value = rpcObject.getValue();

Usted sólo puede transferir tan fácilmente uno de su tipo de encargo IsSerializable:

CustomDTO customDto= new CustomDTO(); // CustomDTO implements IsSerializable
customDto.setYourProperty(to_some_value);
RpcObject rpcObject = new RpcObject();
rpcObject.setValue(customDto);

Y de nuevo, más tarde en el cliente o servidor, el valor puede ser recuperado fácilmente (sin casting):

CustomDTO customDto = rpcObject.getValue();

Usted puede envolver con la misma facilidad como algo java.util.ArrayList:

List list = new ArrayList();  // Notice: no generics parameterization needed!
list.add("This is a string");
list.add(10);
list.add(new CustomDTO());

RpcObject rpcObject = new RpcObject();
rpcObject.setValue(list);

Y una vez más, más tarde en el cliente o el código del servidor, se puede obtener la lista de vuelta con:

List list = rpcObject.getValue();

Después de mirar la "lista blanca" en RpcObject, puede estar inclinado a pensar que solamente List<String> habría sido en lista blanca; sería un error ;-) Mientras todos los valores añadidos a la List son IsSerializable u objetos de tipos de JRE que GWT-RPC solo sabe cómo serializar, entonces usted estará listo . Sin embargo, si usted no necesita lista blanca tipos adicionales, por ejemplo, un tipo de una biblioteca de terceros que utiliza java.io.Serializable en lugar de IsSerializable pueden necesitar ser individualmente blanco-listados (vea la implementación de RpcObject para más detalles) , pueden ser añadidos como nuevos campos directamente en RpcObject, o para mantener la cabeza más baja en los casos comunes, añadirlos a una subclase de RpcObject y el uso de la subclase sólo cuando sea necesario (ya que es una subclase, ninguno de su cliente o servidor firmas de los métodos tendrían que cambiar el uso del tipo RpcObject genérico).

Estoy utilizando esta estrategia para resolver problemas casi idénticos a los descritos por su creador original. espero queotra puede resultar una técnica útil también, pero como siempre, su kilometraje puede variar ... Si la escuela de pensamiento GWT ha avanzado más allá de esta técnica, por favor, comentar y me dejó saber!

-Jeff

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.user.client.rpc.IsSerializable;

public class RpcObject implements IsSerializable {
    protected HashMap<String, IsSerializable> rpcObjectWrapper = new HashMap<String, IsSerializable>();

    /*
     * NOTE: The following fields are here to
     * trick/fool/work-around/whatever-you-want-to-call-it GWT-RPC's
     * serialization policy. Having these types present, even though their
     * corresponding fields are never used directly, enables GWT-RPC to
     * serialize/deserialize these primitive types if they are encountered in
     * the rpcWrapperObject! Of course GWT-RPC already knows how to serialize
     * all these primitive types, but since, for example, String doesn't
     * implement GWT's IsSerializable interface, GWT has no expectation that it
     * should ever be allowed in the rpcWrapperObject instance (and thus String,
     * as well as all the other Java primitives plus Arrays of such types as
     * well as List, Set, and Map, won't be part of the serialization policy of
     * the RpcObject type). This is unfortunate because thanks to java type
     * erasure, we can easily stuff Strings, Integers, etc into the wrapper
     * without any issues; however, GWT-RPC will cowardly refuse to serialize
     * them. Thankfully, it appears that the serialization policy is for the
     * RpcObject type as a whole rather than for the rpcObjectWrapper field
     * specifically. So, if we just add some dummy fields with these "primitive"
     * types they will get added to the serialization policy (they are
     * effectively white-listed) of the type as a whole, and alas, GWT-RPC stops
     * cowardly refusing to serialize them.
     */
    protected Byte _byte;
    protected Short _short;
    protected Integer _integer;
    protected Long _long;
    protected Float _float;
    protected Double _double;
    protected Date _date;
    protected Boolean _boolean;

    protected Byte[] _bytes;
    protected Short[] _shorts;
    protected Integer[] _integers;
    protected Long[] _longs;
    protected Float[] _floats;
    protected Double[] _doubles;
    protected Date[] _dates;
    protected Boolean[] _booleans;

    protected List<String> _list;
    protected Set<String> _set;
    protected Map<String, String> _map;

    public RpcObject() {
        super();
    }

    @SuppressWarnings("unchecked")
    public <X> X getValue() {
        HashMap h = (HashMap) rpcObjectWrapper;
        X value = (X) h.get("value");
        return value;
    }

    @SuppressWarnings("unchecked")
    public void setValue(Object value) {
        HashMap h = (HashMap) rpcObjectWrapper;
        h.put("value", value);
    }
}

Si agrega una manera similar un campo ArrayList Object oa un objeto serializable, el compilador GWT no tiene más remedio que incluir todas las variantes posibles en su compilación. Usted está declarando esencialmente puedo enviar nada usando este campo , por lo que el compilador se asegura de que usted es capaz de enviar nada.

La solución es declarar, usando parámetros genéricos, los tipos específicos que está enviando. Esto podría requerir la división en múltiples parámetros o clases, pero sí mantener el tamaño del código y compilar tiempo de inactividad.

Usted tendrá que ayudar a GWT por ser muy preciso en lo que regrese. Una solución típica es utilizar una interfaz de clase raíz o marcador y declarar que el método RPC devuelve un ArrayList, entonces GWT puede recortar hacia abajo los tipos posibles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top