GWT, the Google Web Toolkit for client-side web programming, contains several client/server communication frameworks. The « traditional » one is called GWT-RPC. GWT-RPC encapsulates the serialization/deserialization of objects, and all the protocol plumbing.
This is usually fine for most use cases, but I needed to explicitely serialize objects on the client side, and deserialize them on the server side.
Use case : I need to call a servlet from my GWT application, to open a document (generated server-side) in a new windows – using window.open()
Solution : create a standard GWT-RPC, declaring a « fake » method containing all the parameter types that we need to explicitly serialize. This will generate a correct GWT « serialization policy ». Then, server side, implement the GWT Service servlet, and override the doGet
with your code.
Create the standard GWT-RPC interfaces :
The interface declares a fake method, with the only goal to allow the type we want to add in the serialization process (here, we have OutputTypeEnum, RepositoryServiceEnum and FBBaseFilterPagingLoadConfig).
@RemoteServiceRelativePath("../fastbiz/service/recordUpload")
public interface RecordUploadService extends RemoteService {
// Fake
void fakeModel(OutputTypeEnum outputType, RepositoryServiceEnum repository, FBBaseFilterPagingLoadConfig config) throws FBException;
}
public interface RecordUploadServiceAsync {
// Fake
void fakeModel(OutputTypeEnum outputType,RepositoryServiceEnum repository,FBBaseFilterPagingLoadConfig config, AsyncCallback<Void> callback);
}
- Client side :
// Creating factory. Interface of any remote service can be used
SerializationStreamFactory factory = (SerializationStreamFactory) GWT.create(RecordUploadService.class);
// Creating stream writer
SerializationStreamWriter writer = factory.createStreamWriter();
// Serializing object
String serializedOutputType = null;
String serializedRepositoryIdentifier = null;
try {
writer.writeObject(outputType);
// Getting serialized object content
serializedOutputType = URL.encodeQueryString(writer.toString());
writer = factory.createStreamWriter();
writer.writeObject(listWindow.getRepositoryIdentifier());
// Getting serialized object content
serializedRepositoryIdentifier = URL.encodeQueryString(writer.toString());
writer = factory.createStreamWriter();
PagingLoadConfig config = listWindow.getConfig();
writer.writeObject(config);
} catch (SerializationException e) {
e.printStackTrace();
}
// Getting serialized object content
String serializedConfig = URL.encodeQueryString(writer.toString());
Window.open(Upload.EXPORT_BASE_URL + "?" + Upload.PARAM_OUTPUT_TYPE + "="
+ serializedOutputType + "&"
+ Upload.PARAM_REPOSITORY_IDENTIFIER + "="
+ serializedRepositoryIdentifier + "&"
+ Upload.PARAM_PAGING_LOAD_CONFIG + "="
+ serializedConfig, "_blank", null);
- Server side :
You implement the service interface, and override the GET method that way:
public class RecordUploadServiceImpl extends RemoteServiceServlet implements com.fastbiz.client.service.RecordUploadService {
private static final long serialVersionUID = 9107309941962048452L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
// Ensure the thread-local data fields have been initialized
try {
// Store the request & response objects in thread-local storage.
synchronized (this) {
if (perThreadRequest == null) {
perThreadRequest = new ThreadLocal<HttpServletRequest>();
}
if (perThreadResponse == null) {
perThreadResponse = new ThreadLocal<HttpServletResponse>();
}
perThreadRequest.set(request);
perThreadResponse.set(response);
}
processGet(request, response);
} catch (Throwable e) {
// Give a subclass a chance to either handle the exception or
// rethrow it
doUnexpectedFailure(e);
} finally {
// null the thread-locals to avoid holding request/response
perThreadRequest.set(null);
perThreadResponse.set(null);
}
}
protected void processGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (Upload.TYPE_LIST.equals(origin)) {
// Initializing stream reader
ServerSerializationStreamReader streamReader = new ServerSerializationStreamReader(
Thread.currentThread().getContextClassLoader(), this);
RepositoryServiceEnum recordType;
FilterPagingLoadConfig config;
OutputTypeEnum outputType;
try {
// Filling stream reader with data
streamReader.prepareToRead(request.getParameter(Upload.PARAM_OUTPUT_TYPE));
// Reading deserialized object from the stream
outputType = (OutputTypeEnum) streamReader.readObject();
} catch (SerializationException e1) {
throw new ServletException("Unable to deserialize parameters",
new FBException(e1));
}
try {
// Filling stream reader with data
streamReader.prepareToRead(request.getParameter(Upload.PARAM_REPOSITORY_IDENTIFIER));
// Reading deserialized object from the stream
recordType = (RepositoryServiceEnum) streamReader.readObject();
} catch (SerializationException e1) {
throw new ServletException("Unable to deserialize parameters",
new FBException(e1));
}
try {
// Filling stream reader with data
streamReader.prepareToRead(request.getParameter(Upload.PARAM_PAGING_LOAD_CONFIG));
// Reading deserialized object from the stream
config = (FilterPagingLoadConfig) streamReader.readObject();
} catch (SerializationException e1) {
throw new ServletException("Unable to deserialize parameters",
new FBException(e1));
}
}
}
@Override
public void fakeBaseModel(OutputTypeEnum outputType, RepositoryServiceEnum repository, FBBaseFilterPagingLoadConfig config) throws FBException {
}
}
Laisser un commentaire