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.