Как добавить тип в белый список политики сериализации GWT?

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

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

Ответ 1

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

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

Приведёт к тому, что ArrayList и Date будут включены в белый список.

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

public Object getObjectForString(String str);

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

Ответ 2

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

Dummy dummy(Dummy d);

Реализация выполняется именно так:

Dummy dummy(Dummy d) { return d; }

И интерфейс async будет иметь следующее:

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

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

Пример Dummy class:

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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

- Андрей

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

Ответ 7

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

Я использую 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 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;
 }
}

Ответ 8

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

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

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

Ответ 9

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

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 = [email protected]
    at com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter.serialize(ServerSerializationStreamWriter.java:619)