Как добавить тип в белый список политики сериализации GWT? - PullRequest
35 голосов
/ 26 сентября 2008

Сериализатор GWT имеет ограниченную поддержку java.io.Serializable, но по соображениям безопасности существует белый список поддерживаемых типов. В документации, которую я нашел, например эта запись FAQ говорится, что любые типы, которые вы хотите сериализовать, "должны быть включены в белый список политики сериализации", и что список создается во время компиляции, но не ' Объяснить, как компилятор решает, что входит в белый список.

Сгенерированный список содержит несколько типов, которые являются частью стандартной библиотеки, такие как java.lang.String и java.util.HashMap. Я получаю сообщение об ошибке при попытке сериализации java.sql.Date, которая реализует интерфейс Serializable, но отсутствует в белом списке. Как я могу добавить этот тип в список?

Ответы [ 9 ]

30 голосов
/ 14 июня 2009

Существует обходной путь: определите новый класс Dummy с полями-членами всех типов, которые вы хотите включить в сериализацию. Затем добавьте метод к вашему интерфейсу RPC:

Dummy dummy(Dummy d);

Реализация просто так:

Dummy dummy(Dummy d) { return d; }

Асинхронный интерфейс будет иметь это:

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

Компилятор GWT подберет это, и поскольку класс Dummy ссылается на эти типы, он включит их в белый список.

Пример Dummy класс:

public class Dummy implements IsSerializable {
    private java.sql.Date d;
}
11 голосов
/ 28 сентября 2008

Любые конкретные типы, которые вы включаете в интерфейс службы, и любые типы, на которые они ссылаются, будут автоматически добавляться в белый список, если они реализуют java.io.Serializable, например:

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

В результате ArrayList и Date будут включены в белый список.

Становится сложнее, если вы попытаетесь использовать java.lang.Object вместо определенных типов:

public Object getObjectForString(String str);

Потому что компилятор не знает, что делать в белом списке. В этом случае, если на объекты не ссылаются нигде в интерфейсе службы, необходимо явно пометить их с помощью интерфейса IsSerializable, иначе он не позволит вам передать их через механизм RPC.

7 голосов
/ 26 сентября 2008

Белый список создается компилятором GWT и содержит все записи, обозначенные интерфейсом маркера IsSerializable.

Чтобы добавить тип в список, вам просто нужно убедиться, что класс реализует интерфейс IsSerializable.

Кроме того, для правильной работы сериализации класс должен иметь конструктор по умолчанию no arg (при необходимости конструктор может быть закрытым). Также, если класс является внутренним, он должен быть помечен как статический.

2 голосов
/ 05 августа 2009

ИМХО самый простой способ программного доступа к белому списку - создать класс, подобный следующему:

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

Затем включите его в пакет .client и ссылку из службы RPC (чтобы она анализировалась компилятором).

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

1 голос
/ 10 апреля 2010

Белый список создается компилятором gwt и содержит все записи, обозначенные интерфейсом маркера IsSerializable.

Чтобы добавить тип в список, вам просто нужно убедиться, что класс реализует интерфейс IsSerializable.

- Андрей

Это, наверное, самое простое решение. Единственное, что нужно помнить, это то, что все классы, которые вы хотите сериализовать, должны иметь конструктор public, no-аргумент и (в зависимости от требований) методы установки для полей-членов.

1 голос
/ 07 октября 2009

, чтобы обеспечить желаемый результат, удалить все war/<app>/gwt/*.gwt.rpc

0 голосов
/ 06 февраля 2013

У меня была эта проблема, но в итоге ее проблема была возвращена к строке кода в моем сериализуемом объекте:

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

Не было никаких других жалоб до того, как исключение было зафиксировано в:

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

И бизнес-конец трассировки стека:

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 = net.your.class@9c7edce
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:619)
0 голосов
/ 23 сентября 2011

Я обнаружил, что просто положить его в пакет клиента или использовать его в фиктивном интерфейсе службы было недостаточно, так как казалось, что система оптимизировала его.

Мне было проще всего создать класс, производный от одного из типов, уже используемых в интерфейсе службы, и вставить его в клиентский пакет. Больше ничего не нужно.

public class GWTSerializableTypes extends SomeTypeInServiceInterface implements IsSerializable {
    Long l;
    Double d;
    private GWTSerializableTypes() {}
}
0 голосов
/ 26 октября 2009

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

Я использую GWT с GWTController, так как я использую Spring, который я изменил, как описано в этом сообщении . Сообщение объясняет, как изменить GrailsRemoteServiceServlet, но GWTController вызывает RPC.decodeRequest () и RPC.encodeResponseForSuccess () таким же образом.

Это последняя версия GWTController, которую я использую:

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