2008-09-26 5 views
35

GWT's Serializer hat java.io.Serializable Unterstützung begrenzt, aber aus Sicherheitsgründen gibt es eine Whitelist von Typen, die es unterstützt. Die Dokumentation, die ich gefunden habe, zum Beispiel this FAQ entry besagt, dass alle Typen, die Sie serialisieren möchten, "in die Whitelist der Serialisierungsrichtlinie aufgenommen werden müssen" und dass die Liste zur Kompilierzeit generiert wird, aber nicht erklärt, wie der Compiler entscheidet, was geht auf der Whitelist. Die generierte Liste enthält eine Reihe von Typen, die Teil der Standardbibliothek sind, wie java.lang.String und java.util.HashMap. Ich bekomme einen Fehler beim Versuch, java.sql.Date zu serialisieren, die die Serializable Schnittstelle implementiert, aber nicht auf der Whitelist ist. Wie kann ich diesen Typ zur Liste hinzufügen?Wie füge ich einen Typ zu GWTs Serialization Policy Whitelist hinzu?

Antwort

12

Alle spezifischen Typen, die Sie in Ihrem Service-Schnittstelle und alle Arten umfassen, die sie verweisen automatisch die weiße Liste gesetzt werden, solange sie implementieren java.io.Serializable, zB:

public String getStringForDates(ArrayList<java.util.Date> dates); 

in Arraylist führen und Datum, das beide auf der Whitelist enthalten sind.

Es wird schwieriger, wenn Sie versuchen, und verwenden java.lang.Object statt spezifische Typen:

public Object getObjectForString(String str); 

Da der Compiler nicht weiß, was zu weißen Liste. In diesem Fall müssen Sie, wenn die Objekte nirgendwo in Ihrer Service-Schnittstelle referenziert werden, diese explizit mit der IsSerializable-Schnittstelle markieren, da Sie sonst nicht über den RPC-Mechanismus weitergeleitet werden.

7

Die Whitelist wird vom GWT-Compiler generiert und enthält alle Einträge, die von der IsSerializable-Markierungsschnittstelle angegeben werden.

Um einen Typ zur Liste hinzuzufügen, müssen Sie nur sicherstellen, dass die Klasse die IsSerializable-Schnittstelle implementiert.

Damit die Serialisierung korrekt funktioniert, muss die Klasse einen Standardargkonstruktor haben (Konstruktor kann bei Bedarf privat sein). Auch wenn die Klasse ein Inneres ist, muss sie als statisch markiert werden.

+11

Es sollte hinzugefügt werden - die Klasse muss auch einen öffentlichen Standard-No-Args-Konstruktor haben. Die Implementierung der IsSerializable-Schnittstelle ohne das ist nicht genug. Fand das auf die harte Tour nach einer Stunde Debugging aus :) –

+2

@AdrianPetrescu Das ist nicht ganz korrekt. Der Konstruktor "no args" darf privat sein, muss aber trotzdem da sein. Außerdem darf die Klasse selbst nicht privat sein, und wenn es sich um eine innere Klasse handelt, muss sie statisch sein. Und die Klasse darf keine endgültigen nicht statischen Felder haben. – FrankPl

29

Es gibt eine Problemumgehung: Definieren Sie eine neue Dummy Klasse mit Elementfeldern aller Typen, die in die Serialisierung einbezogen werden sollen. Dann, ein Verfahren zur RPC-Schnittstelle hinzu:

Dummy dummy(Dummy d); 

Die Implementierung ist einfach dies:

Dummy dummy(Dummy d) { return d; } 

Und die Asynchron-Schnittstelle dies hat:

void dummy(Dummy d, AsyncCallback< Dummy> callback); 

Die GWT-Compiler werden diese holen up, und weil die Klasse Dummy diese Typen referenziert, werden sie in die Whitelist aufgenommen.

Beispiel Dummy Klasse:

public class Dummy implements IsSerializable { 
    private java.sql.Date d; 
} 
2

IMHO die einfachste Art und Weise weiße Liste zuzugreifen programmatisch eine Klasse ähnlich wie dies zu schaffen ist:

public class SerializableWhitelist implements IsSerializable { 
    String[] dummy1; 
    SomeOtherThingsIWishToSerialize dummy2; 
} 

Dann schließen sie in dem .client Paket und Verweise aus dem RPC-Dienst (so wird es vom Compiler analysiert).

ich keinen besseren Weg finden konnte, Tranfer von unparameterized Karten zu ermöglichen, was offensichtlich ist, was Sie manchmal brauchen, um mehr Basisdienste zu schaffen ...

+1

Und das funktioniert, ohne diesen Typ zu einer RPC-Schnittstelle hinzufügen? –

+1

Nein, das habe ich nicht gerade versucht. – devconsole

1

, um sicherzustellen, das gewünschte Ergebnis all war/<app>/gwt/*.gwt.rpc

löscht
0

Für jeden, der die gleiche Frage haben und findet keine früheren Antworten zufriedenstellend ...

ich verwende GWT mit GWTController, da ich Frühling bin mit, die ich als in this message beschrieben modifiziert. Die Nachricht erläutert, wie GrailsRemoteServiceServlet geändert wird, aber GWTController ruft RPC.decodeRequest() und RPC.encodeResponseForSuccess() auf die gleiche Weise auf.

Dies ist die letzte Version von GWTController Ich verwende:

/** 
* Used to instantiate GWT server in Spring context. 
* 
* Original version from <a href="http://docs.google.com/Doc?docid=dw2zgx2_25492p5qxfq&hl=en">this tutorial</a>. 
* 
* ...fixed to work as explained <a href="http://blog.js-development.com/2009/09/gwt-meets-spring.html">in this tutorial</a>. 
* 
* ...and then fixed to use StandardSerializationPolicy as explained in 
* <a href="http://markmail.org/message/k5j2vni6yzcokjsw">this message</a> to allow 
* using Serializable instead of IsSerializable in model. 
*/ 
public class GWTController extends RemoteServiceServlet implements Controller, ServletContextAware { 

// Instance fields 

private RemoteService remoteService; 

private Class<? extends RemoteService> remoteServiceClass; 

private ServletContext servletContext; 

// Public methods 

/** 
    * Call GWT's RemoteService doPost() method and return null. 
    * 
    * @param request 
    *   The current HTTP request 
    * @param response 
    *   The current HTTP response 
    * @return A ModelAndView to render, or null if handled directly 
    * @throws Exception 
    *    In case of errors 
    */ 
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { 
    doPost(request, response); 
    return null; // response handled by GWT RPC over XmlHttpRequest 
} 

/** 
    * Process the RPC request encoded into the payload string and return a string that encodes either the method return 
    * or an exception thrown by it. 
    * 
    * @param payload 
    *   The RPC payload 
    */ 
public String processCall(String payload) throws SerializationException { 
    try { 
    RPCRequest rpcRequest = RPC.decodeRequest(payload, this.remoteServiceClass, this); 

    // delegate work to the spring injected service 
    return RPC.invokeAndEncodeResponse(this.remoteService, rpcRequest.getMethod(), rpcRequest.getParameters(), rpcRequest.getSerializationPolicy()); 
    } catch (IncompatibleRemoteServiceException e) { 
    return RPC.encodeResponseForFailure(null, e); 
    } 
} 

/** 
    * Setter for Spring injection of the GWT RemoteService object. 
    * 
    * @param RemoteService 
    *   The GWT RemoteService implementation that will be delegated to by the {@code GWTController}. 
    */ 
public void setRemoteService(RemoteService remoteService) { 
    this.remoteService = remoteService; 
    this.remoteServiceClass = this.remoteService.getClass(); 
} 

@Override 
public ServletContext getServletContext() { 
    return servletContext; 
} 

public void setServletContext(ServletContext servletContext) { 
    this.servletContext = servletContext; 
} 
} 
1

Die Weiße Liste der GWT-Compiler generiert und enthält alle Einträge, die von der IsSerializable Markierungsschnittstelle bezeichnet werden.

Um einen Typ zur Liste hinzuzufügen, müssen Sie nur sicherstellen, dass die Klasse die IsSerializable-Schnittstelle implementiert.

- Andrej

Dies ist wahrscheinlich die einfachste Lösung. Das einzige, an das Sie sich erinnern sollten, ist, dass alle Klassen, die Sie serialisieren möchten, den Konstruktor "public, no-argument" und (abhängig von den Anforderungen) Setter-Methoden für die Mitgliedsfelder haben sollten.

+0

Die Sichtbarkeit des Standardkonstruktors ist nicht wichtig. Sie brauchen nur einen Null-Arg-Standardkonstruktor jeder Sichtbarkeit (sogar ein privater Wille tut das) – thomaux

0

Ich fand, dass es einfach nicht ausreichte, es in das Client-Paket zu packen oder es in einer Dummy-Service-Schnittstelle zu verwenden, da es schien, dass das System es wegoptimierte.

Ich fand es am einfachsten, eine Klasse zu erstellen, die von einem der Typen abgeleitet ist, die bereits in der Service-Schnittstelle verwendet wurden, und sie in das Client-Paket zu stecken. Nichts anderes benötigt.

public class GWTSerializableTypes extends SomeTypeInServiceInterface implements IsSerializable { 
    Long l; 
    Double d; 
    private GWTSerializableTypes() {} 
} 
0

hatte ich dieses Problem, aber das Problem wieder in eine Zeile Code in meinem Serializable Objektnachführungsrahmen endete:

Logger.getLogger(this.getClass().getCanonicalName()).log(Level.INFO, "Foo"); 

Es gibt keine andere Beschwerden waren, bevor die Ausnahme in verfängt:

@Override 
    protected void serialize(Object instance, String typeSignature) 
     throws SerializationException { 
    assert (instance != null); 

    Class<?> clazz = getClassForSerialization(instance); 

    try { 
     serializationPolicy.validateSerialize(clazz); 
    } catch (SerializationException e) { 
     throw new SerializationException(e.getMessage() + ": instance = " + instance); 
    } 
    serializeImpl(instance, clazz); 
    } 

Und das Geschäft Ende des Stack-Trace ist:

com.google.gwt.user.client.rpc.SerializationException: Type 'net.your.class' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.: instance = [email protected] 
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:619)