As has been discussed previously in various venues, I have a mostly-working 
port of GWT-RPC that drops the use of legacy GWT APIs like Generators and 
JSNI, future-proofing both beyond GWT 2.x, and making it functional in 
other runtimes (JVM, Android, TeaVM, etc). It isn't perfect, and isn't 
quite complete, but before I work on softening those rough edges, I wanted 
to have a conversation here about whether it should remain a part of GWT 
going forward, and be migrated to the org.gwtproject package/groupId, and 
hosted at github.com/gwtproject.

There are two main reasons I see that would lead us to avoid doing this - 
RPC doesn't enjoy the popularity it once did, and the use of my current 
draft implementation could be considered to be far enough a way from the 
old Generator implementation that it might seem to be a different tool 
entirely. 

 * RPC-based mechanisms in general seem to be out of favor (though with 
gRPC gaining popularity, the idea might be coming back), with REST (whether 
JSON, Protobuf, or whatever else you like) leading in one direction and 
query mechanisms like GraphQL in another. I don't want to debate the pros 
and cons of these, or even to break down how "GWT-RPC" can be treated like 
a RPC or query mechanism, only to note that if RPC is considered by itself 
to be "too old-school", that might be are a reason to do nothing more than 
provide upgrade paths *within GWT itself*. 

 * In order to support being run by annotation processors in a performant 
way, my particular implementation all but mandates that the RPC interfaces 
and beans exist in their own "shared" project, apart from either client or 
server. Arguably this is a best practice to begin with, but it hasn't 
actually been required. Additionally, to support external dependencies 
(either other projects within your own product, or outside artifacts like 
the JRE or Guava that might have serializable types you'd be interested in) 
a manifest of some kind is required to point at the classes that should be 
considered while compiling. Presently this is supported through annotation 
processor arguments, but other mechanisms could be supported as well, but 
nothing as simple and obvious as "just assume that all possible subclasses 
will work" that GWT2's RPC supports. Reading private members isn't 
supported either - it is assumed that either those members will be 
non-private, or that getters and setters will be provided.

These two points probably need to be weighed relative to each other as 
well: we could decide that as long as the migration path for 90% of 
projects out there is simple enough that despite being out of favor, at 
least part of this tool should end up in org.gwtproject for now. Or, 
perhaps despite its continued popularity, the project is different enough 
that it shouldn't be included in org.gwtproject merely due to having its 
roots in "classic" GWT-RPC.

--

A quick technical overview - I don't want to get bogged down in this 
discussion just yet, just providing a summary to inform the topic at hand 
(though I'll be happy to provide more details as it helps to make this 
decision).

The project is composed of two annotation processors, and is intended to 
support a variety of use cases out of the box:
 * old pipe-delimited string format, or TypedArray/ByteBuffer based 
encoding (including not writing Strings to the typedarray at all but 
leaving them in a plain JS array for cheaper copying between the window and 
workers)
 * transport tools for page/worker, websockets, and fetch/xhr calls
 * interface-based approach to handling streams allowing other 
implementations to be added or further specialized, and transport 
mechanisms to be built per-platform so interfaces, beans, and generated 
serializers can be reused between platforms, easily enabling adding new 
platforms, or devising your own stream formats or transport mechanisms.

At runtime, the serialization stream interface is nearly identical to the 
old one, with the addition of one additional method when reading from the 
stream, to generalize mitigation on a class of attack that GWT-RPC 
historically only handled in the servlet. No reflection is used in the 
server implementation for de/serializing fields in objects, but it is 
instead assumed that either a field serializer has been created by the code 
generation mechanism, or a custom field serializer has been provided. 

Instead of a .gwt.rpc file on the server to enumerate types that are 
serializable and a JSNI map on the client, a single class is generated to 
describe this for each platform - server gets one, and client gets another 
for example, and these are almost certainly compliments of each other. 
Avoiding the JSNI map may pose a small risk at increasing generated code 
size, but I've tried to mitigate this by generating specific serializer 
types which describe exactly which operations are supported, so that any 
pruning step when compiling code can delete as much code as possible (and 
support weird cases like only reading a type sent from the server, but both 
reading and writing that same type when communicate with a web worker).

The SerializableTypeOracleBuilder remains at the heart of the code 
generation mechanism, updated to use TypeMirrors and Elements instead of 
GWT's JType hierarchy. Instead of being invoked by the RemoteService code 
generator, this is instead triggered by its own annotation, expected to be 
found on an interface with helper methods to add various types to an 
existing stream, or decode a stream and read expected data. This interface 
in turn is expected to be generated by another, higher-level annotation 
processor, based on the specific use case (XMLHttpRequest, WebSocket, etc). 
The built-in "high level" processor implementation takes an interface full 
of asynchronous interface methods and generates boilerplate to serialize 
each method's arguments as necessary. Presently, there is one such high 
level processor, which relies on each interface it sees to either offer 
specifics on a base class to extend, or extend another interface which in 
turn provides those specifics - I've planned to add a second ("high-er" 
level?) processor, just for the purpose of allowing a synchronous interface 
to be provided and implemented on the server, and the async instance 
generated automatically.


Potential future work: 
 * "Opaque serialization" for server-originating objects to sign them and 
return them to the server unchanged, for use in eventually implementing the 
JPA features (which otherwise have been left out so far due to the easy 
attack vector it presents).
 * More options for automatic de/serialization, possibly including some 
kind of "violator pattern" tool, support for builder/factories, 
@ConstructorProperties for final fields, etc.
 * Allow disabling polymorphism in whole or in part to save bytes over the 
wire (and more easily support non-Java remote endpoints).
 * "Allocation-free" (or at least "reduced allocation") 
serialization/deserialization, for memory/allocation constrained 
situations, allowing bean-like data to be read or written, but handled on 
at least one endpoint on a field-by-field basis.

--

So, as I continue to polish this and prepare to push builds for others to 
begin trying, I would like to start making packages and groupIds 
consistent. If the direction seems to be that it doesn't belong in 
gwtproject, that's fine by me, plenty of other popular GWT libraries live 
outside the official project, but if we think it might belong here, then to 
avoid later churn in downstream projects, I'd like to start adopting the 
org.gwtproject namespace right away.

-- 
You received this message because you are subscribed to the Google Groups "GWT 
Contributors" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to google-web-toolkit-contributors+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/google-web-toolkit-contributors/ba0b000c-2228-4897-94a0-cc9faa42e60f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to