كيف أقوم بإضافة نوع إلى القائمة البيضاء لسياسة التسلسل الخاصة بـ GWT؟

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

سؤال

مُسلسل GWT محدود java.io.Serializable الدعم، ولكن لأسباب أمنية توجد قائمة بيضاء بالأنواع التي يدعمها.الوثائق التي وجدتها، على سبيل المثال إدخال الأسئلة الشائعة هذا يقول أن أي أنواع تريد إجراء تسلسل لها "يجب أن يتم تضمينها في القائمة البيضاء لسياسة التسلسل"، وأن القائمة يتم إنشاؤها في وقت الترجمة، ولكنها لا تشرح كيف يقرر المترجم ما يتم إدراجه في القائمة البيضاء.

تحتوي القائمة التي تم إنشاؤها على عدد من الأنواع التي تعد جزءًا من المكتبة القياسية، مثل java.lang.String و java.util.HashMap.أحصل على خطأ عند محاولة إجراء تسلسل java.sql.Date, ، والذي ينفذ Serializable الواجهة، ولكنها ليست في القائمة البيضاء.كيف يمكنني إضافة هذا النوع إلى القائمة؟

هل كانت مفيدة؟

المحلول

سيتم إدراج أي أنواع محددة تقوم بتضمينها في واجهة الخدمة الخاصة بك وأي أنواع تشير إليها في القائمة البيضاء تلقائيًا، طالما أنها تطبق java.io.Serializable، على سبيل المثال:

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

سيؤدي إلى إدراج ArrayList وDate في القائمة البيضاء.

يصبح الأمر أكثر صعوبة إذا حاولت استخدام java.lang.Object بدلاً من أنواع محددة:

public Object getObjectForString(String str);

لأن المترجم لا يعرف ما الذي يجب إضافته إلى القائمة البيضاء.في هذه الحالة، إذا لم تتم الإشارة إلى الكائنات في أي مكان في واجهة الخدمة الخاصة بك، فيجب عليك وضع علامة عليها بشكل صريح باستخدام واجهة IsSerializable، وإلا فلن يسمح لك بتمريرها عبر آلية RPC.

نصائح أخرى

هناك حل بديل:تحديد جديد 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;
}

يتم إنشاء القائمة البيضاء بواسطة برنامج التحويل البرمجي GWT وتحتوي على كافة الإدخالات التي تم تعيينها بواسطة واجهة علامة IsSerializable.

لإضافة نوع إلى القائمة، تحتاج فقط إلى التأكد من أن الفصل يطبق واجهة IsSerializable.

بالإضافة إلى ذلك، لكي تعمل عملية التسلسل بشكل صحيح، يجب أن يكون لدى الفصل مُنشئ افتراضي بدون وسيط (يمكن أن يكون المُنشئ خاصًا إذا لزم الأمر).وأيضًا إذا كان الفصل داخليًا، فيجب وضع علامة عليه على أنه ثابت.

IMHO إن أبسط طريقة للوصول إلى القائمة البيضاء برمجيًا هي إنشاء فئة مشابهة لما يلي:

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

ثم أدخله في .client الحزمة والمرجع من خدمة RPC (لذلك يتم تحليلها بواسطة المترجم).

لم أتمكن من العثور على طريقة أفضل لتمكين نقل الخرائط غير ذات المعلمات، وهو ما تحتاجه أحيانًا لإنشاء خدمات أكثر عمومية...

يتم إنشاء القائمة البيضاء بواسطة برنامج التحويل البرمجي gwt وتحتوي على كافة الإدخالات التي تم تعيينها بواسطة واجهة علامة IsSerializable.

لإضافة نوع إلى القائمة، تحتاج فقط إلى التأكد من أن الفصل يطبق واجهة IsSerializable.

-- أندريه

ربما هذا هو الحل الأسهل.الشيء الوحيد الذي يجب تذكره مع هذا هو أن جميع الفئات التي تريد إجراء تسلسل لها يجب أن تحتوي على مُنشئ "عام بدون وسيطات" وطرق ضبط (حسب المتطلبات) لحقول الأعضاء.

لضمان النتيجة المرجوة حذف الكل war/<app>/gwt/*.gwt.rpc

إلى كل من سيكون لديه نفس السؤال ولم يجد الإجابات السابقة شافية...

أنا أستخدم 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;
 }
}

لقد وجدت أن مجرد وضعها في حزمة العميل أو استخدامها في واجهة خدمة وهمية لم يكن كافيًا حيث يبدو أن النظام قد قام بتحسينها.

لقد وجدت أنه من الأسهل إنشاء فئة مشتقة من أحد الأنواع المستخدمة بالفعل في واجهة الخدمة ولصقها في حزمة العميل.لا حاجة لأي شيء آخر.

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

لقد واجهت هذه المشكلة ولكن انتهى بي الأمر بتتبع المشكلة مرة أخرى إلى سطر من التعليمات البرمجية في الكائن القابل للتسلسل الخاص بي:

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)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top