RequestFactory & AutoBeans
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against GWT 2.13.1 (released 2026-06-19), gwt-maven-plugin 1.3.0 (net.ltgt.gwt.maven), JDK 21 running the compiler with -sourceLevel 17, the Jakarta Servlet 6 server of the Bookshelf scenario (Jetty 12.1.10 through the Maven plugin) and Hibernate Validator 4.1.0.Final on the server, checked on 2026-10-09.
RequestFactory touches every layer: the proxy interfaces and the RequestFactory interface are shared code (the compiler turns them into JavaScript and the server loads them as ordinary classes), the generated client and the Receiver callbacks are client code, the entities, services, locators and the servlet are server code, and two build steps are specific to it (an <inherits> line and an annotation processor).
AutoBeans are shared code in the same way.
Every output block was produced by running the examples: the real RequestFactory client and server in one JVM on JDK 21 (plain JUnit with InProcessRequestTransport), the servlet in Jetty on port 8935 driven with curl, and GWTTestCase tests in HtmlUnit for the generated client and the AutoBeans in a browser engine.
Where a statement comes only from the Developer Guide or from the 2.13.1 source, the text says so.
RequestFactory is the data-oriented sibling of GWT-RPC: instead of calling remote methods on a service, the client manipulates proxies of server-side entities inside a request context, and only the changed properties travel to the server. It is old (it appeared with GWT 2.1) and the Developer Guide has not changed in a long time, so the page spends as much effort on what is stale and on how to decide whether to use it as on the API itself. The decision is in [status] and the comparison with the alternatives is in Choosing between GWT-RPC, RequestFactory and plain JSON for a GWT 2.13 application.
The idea in one example
The Bookshelf client below lists books together with their publisher, then changes the year of one of them.
The proxies and the BookRequest context are the interfaces defined later on this page; nothing in this code knows about HTTP, JSON or the server classes.
public class BookshelfData {
private final BookshelfRequestFactory factory = GWT.create(BookshelfRequestFactory.class);
public BookshelfData(EventBus eventBus, RequestTransport transport) {
factory.initialize(eventBus, transport);
}
public void load(int first, int max, final BooksCallback callback) {
factory.bookRequest().findBookEntries(first, max).with("publisher").fire(
new Receiver<List<BookProxy>>() {
@Override
public void onSuccess(List<BookProxy> books) {
callback.onBooks(books);
}
@Override
public void onFailure(ServerFailure error) {
callback.onError(error.getMessage());
}
});
}
public void changeYear(BookProxy book, int year, final Runnable done) {
BookRequest ctx = factory.bookRequest();
BookProxy editable = ctx.edit(book);
editable.setYear(year);
ctx.persist().using(editable).fire(new Receiver<Void>() {
@Override
public void onSuccess(Void ignored) {
done.run();
}
});
}
}
Three things are different from GWT-RPC:
-
GWT.create(BookshelfRequestFactory.class)is called once;initialize(eventBus, transport)gives the factory anEventBusfor entity-change events and aRequestTransportthat does the HTTP. -
Proxies received from the server are immutable.
edit(book)returns an editable copy bound to the request context, and the setters record the change; the request that is fired afterwards carries onlyyear. -
.with("publisher")lists the relations to send back. RequestFactory never follows relations on its own.
The client code compiles to JavaScript. The same code, compiled with RequestFactorySource.create instead of GWT.create, also runs on a JVM, which is how the server side was tested for this page.
RequestFactory compared with the other options
The Developer Guide describes RequestFactory as an alternative to GWT-RPC for data-oriented services, built around entities (data with a persistent identity) and services. GWT-RPC uses remote methods as building blocks, similar to Java RMI; RequestFactory keeps track of modified objects and sends only the changes, which the guide describes as very lightweight payloads, and it uses its own servlet and its own JSON protocol. The table is a summary of the guide, of the 2.13.1 source and of what was measured here.
| GWT-RPC | RequestFactory | JSON over HTTP (RequestBuilder, fetch, AutoBeans) |
|
|---|---|---|---|
Building block |
A service interface with methods |
An entity proxy, a request context and a service |
A URL and a document |
What the client holds |
The same concrete serialisable classes as the server |
Interfaces implemented by the framework, one per entity |
Overlay types, JsInterop objects or AutoBeans |
Server code |
A servlet that implements the service interface |
Plain entity and service classes, found through annotations |
Any servlet, controller or JAX-RS resource |
Changes |
The whole object is sent back |
Only changed properties are sent |
Whatever you design |
Batching |
One call per request |
Several contexts can be joined in one HTTP request ( |
Whatever you design |
Validation |
Your own code |
JSR-303 on the server, violations returned to the |
Your own code |
Server-side requirement |
|
|
Nothing from GWT |
Used by a non-GWT client |
Not realistic |
The wire format is documented only in the source ( |
Yes |
Status |
Documented; see GWT-RPC for its Java 17 exception-serialisation issue |
See [status] |
Not tied to GWT |
GWT-RPC and RequestBuilder, JSON & XML are the other halves of the comparison; the overview of all options is Client–Server Communication. This page does not repeat them.
Artifacts and setup
The RequestFactory artifacts live in their own group, org.gwtproject.web.bindery, not in org.gwtproject.
All of them were published for 2.13.1 on 2026-06-19 (Maven Central metadata, checked 2026-10-09).
| Artifact | What it contains |
|---|---|
|
A pom that manages the versions of the others. The GWT bill of materials |
|
The compiled client and shared classes (the |
|
The server side for |
|
The same for |
|
The annotation processor and the command-line |
gwt-servlet-jakarta (and gwt-servlet for javax) already contains the RequestFactory server classes, the shared classes and the AutoBean vm package, including RequestFactoryServlet, InProcessRequestTransport and AutoBeanFactorySource (listed in the 2.13.1 jars).
A Bookshelf server that already depends on gwt-servlet-jakarta for GWT-RPC therefore needs only two more dependencies for RequestFactory: javax.validation:validation-api (managed by the GWT BOM at 1.0.0.GA) and requestfactory-apt on the annotation processor path.
Adding requestfactory-server-jakarta on top of gwt-servlet-jakarta works but makes the Jetty Maven plugin print scanned from multiple locations warnings, because the two jars contain the same classes; pick one.
The server module of the Bookshelf therefore adds this to its existing gwt-servlet-jakarta dependency (the processor configuration is in the validation tool section):
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.1.0.Final</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.4</version>
<scope>runtime</scope>
</dependency>
Source: GWT — Request Factory: Wiring
Hibernate Validator 4.1.0.Final is the provider Validation uses for the client; as a server provider here it is the only one that was tried. It needs slf4j-api: the 1.6.1 that it declares and a newer slf4j-simple mixed together failed with a NoSuchMethodError for org.slf4j.helpers.MessageFormatter.format, so keep the slf4j-api and the binding on one version.
The Developer Guide’s list of jars (requestfactory-server.jar, validator-api-1.0.0.GA.jar, a JSR 303 validator) is the same set spelled for a hand-built WEB-INF/lib.
The module file
The compiler needs the RequestFactory module in the module that contains the proxies, and the AutoBean module if you use AutoBeans directly (RequestFactory inherits it itself).
<module>
<inherits name="com.google.gwt.user.User" />
<inherits name="com.google.web.bindery.requestfactory.RequestFactory" />
<inherits name="com.google.web.bindery.autobean.AutoBean" />
<source path="client" />
<source path="shared" />
</module>
RequestFactory.gwt.xml inherits Core, AutoBean, HTTP, LoggingDisabled and User, adds the gwt/client, gwt/ui/client and shared source paths and registers two generators: RequestFactoryGenerator for every type assignable to RequestFactory, and RequestFactoryEditorDriverGenerator for RequestFactoryEditorDriver (see the editors page).
AutoBean.gwt.xml registers AutoBeanFactoryGenerator for every type assignable to AutoBeanFactory.
Both are deferred-binding generators, which is why the factories are created with GWT.create.
The servlet
The Developer Guide registers com.google.web.bindery.requestfactory.server.RequestFactoryServlet.
That class extends javax.servlet.http.HttpServlet and cannot run in a Servlet 5 or 6 container; since 2.11.0 the jakarta variant is the one to use there.
<servlet>
<servlet-name>requestFactoryServlet</servlet-name>
<servlet-class>com.google.web.bindery.requestfactory.server.jakarta.RequestFactoryServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>requestFactoryServlet</servlet-name>
<url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
Source: GWT — Request Factory: Wiring
javax |
jakarta |
|
|---|---|---|
Class |
|
|
Superclass |
|
|
Artifacts |
|
|
Containers |
Servlet 4 and earlier (Jetty 9, Tomcat 9) |
Servlet 5 and 6 (Jetty 11 and later, Tomcat 10 and later, Spring Boot 3) |
Everything else on the server (SimpleRequestProcessor, ServiceLayer, Locator, ServiceLocator, the validation) is shared by both variants.
Only the jakarta class was run for this page (in Jetty 12.1.10). The javax class was inspected with javap in the 2.13.1 jars, not run in a javax container.
The servlet reads two optional init parameters, symbolMapsDirectory and symbolMapsResourcePath, to deobfuscate stack traces of server failures sent by the client logging (the Developer Guide shows WEB-INF/classes/symbolMaps/ and says the application must be compiled with -extras).
The page on logging covers the symbol maps; see Logging, and Server Integration & Deployment covers the servlet container side.
The servlet also exposes getThreadLocalRequest(), getThreadLocalResponse() and getThreadLocalServletContext(), which services use to reach the HTTP transaction (the Bookshelf example uses the request for an authorisation check).
The moving parts
| Type | Layer | Role |
|---|---|---|
|
shared |
Your interface; one method per service stub. Created with |
|
shared |
A unit of work. It creates and edits proxies, accumulates the calls, and sends everything when |
|
shared |
A call to a service method. |
|
shared |
Client view of an entity with identity: adds |
|
shared |
Client view of a value object without identity or version |
|
shared |
Name the domain class a proxy stands for (and, optionally, its |
|
shared |
Name the class that implements a context’s methods (and, optionally, its |
|
shared |
Adds proxy types that are not reachable from the signatures, for example subtypes |
|
server |
Supplies |
|
server |
Supplies the instance on which a service’s instance methods are invoked |
|
client |
Callback: |
|
client |
Event on the |
|
client |
Sends a string and returns a string; the default one POSTs to the host page base URL followed by |
|
server |
Receives the payload, calls |
|
build |
Validate that the client interfaces match the domain classes and generate the lookup class the servlet needs |
Proxies and the RequestFactory interface
An entity proxy is an interface that extends EntityProxy and names its domain class.
Only the getters and setters the client needs have to be declared; the compiler checks that each has a match on the domain class.
@ProxyForName("com.example.bookshelf.server.rf.BookEntity")
public interface BookProxy extends EntityProxy {
Long getId();
Integer getVersion();
String getTitle();
void setTitle(String title);
String getAuthor();
void setAuthor(String author);
int getYear();
void setYear(int year);
PublisherProxy getPublisher();
void setPublisher(PublisherProxy publisher);
}
@ProxyForName("com.example.bookshelf.server.rf.Publisher")
public interface PublisherProxy extends ValueProxy {
String getName();
void setName(String name);
String getCountry();
void setCountry(String country);
}
@ProxyFor(BookEntity.class) is the form used in the Developer Guide. It needs the domain class on the classpath of whoever compiles the proxy.
In the Bookshelf the proxies are in bookshelf-shared, which cannot see the classes of bookshelf-server, so they use @ProxyForName with the class name; the validation step (below) resolves the names on the server.
The same applies to @Service and @ServiceName.
The Developer Guide’s rules, which the validation tool enforces at build time:
-
A proxy must map to a single domain type; every property of the proxy, including inherited ones, must exist on the domain type.
-
Proxies expose bean-style getters and setters only. Getters of proxy type return other proxies, never domain objects. Relations are not populated unless
with("name")names them (dots reach nested properties, for exampleaddress.city). -
getId()andgetVersion()are optional on the proxy. Client code should preferstableId(), whoseEntityProxyIdidentifies the entity even before the server has assigned an id. -
A
ValueProxyneed not expose an id or a version; it is copied by value (the guide’s example is an embedded address). A property whose type extendsValueProxyalso has to be named inwith()to be returned. -
Types that may be used as properties and as request parameters and results are the transportable types: primitives and boxed primitives,
String,Enum,BigInteger,BigDecimal,Date, entity and value proxies, andList,SetandMapof those. -
Proxy types are available on the client when they are referenced from a context method, from another reachable proxy, are a proxy supertype of one, or are listed in
@ExtraTypeson the factory, a context or a proxy.
The factory interface has one method per service stub:
public interface BookshelfRequestFactory extends RequestFactory {
BookRequest bookRequest();
ReviewRequest reviewRequest();
}
RequestFactory also has find(EntityProxyId) (a request that loads one entity by its stable id), getEventBus(), getRequestTransport(), getHistoryToken(EntityProxyId) and getProxyId(String) (stable ids as strings, which fits History & Navigation and Places), and getSerializer(ProxyStore) for saving proxies locally.
The last two were run: for the Bookshelf book with id 2 the history token and the serialised key were both IjIi@0@BOOK_PROXY_TYPE_TOKEN, a base64 JSON id, a strength digit and the type token, and deserialize(BookProxy.class, key) returned the proxy with the title "Effective Java".
The service side
A service stub extends RequestContext and names the server class that implements its methods.
@ServiceName("com.example.bookshelf.server.rf.BookEntity")
public interface BookRequest extends RequestContext {
Request<Long> countBooks();
Request<List<BookProxy>> findBookEntries(int firstResult, int maxResults);
Request<BookProxy> findBook(Long id);
InstanceRequest<BookProxy, Void> persist();
InstanceRequest<BookProxy, Void> remove();
}
The methods of the context do not return values; they return Request<T> objects whose fire(Receiver<T>) is the asynchronous call, like passing an AsyncCallback in GWT-RPC.
The server class does not implement the context. It implements methods with the same names and arguments, mapped as follows (Developer Guide, confirmed by the run):
-
A method that returns
Request<T>returnsTon the server; proxy types become the domain types, soRequest<List<BookProxy>>isList<BookEntity>. -
Such a method is a static method of the service class, or an instance method of the object that a
ServiceLocatorreturns. -
A method that returns
InstanceRequest<BookProxy, Void>is an instance method of the entity and takes no argument; the instance comes fromusing(proxy)on the client. -
If the method is an instance method of a service (with a
ServiceLocator) the proxy can instead be a normal argument.
An entity that implements its own persistence
The simplest server entity is a class with the four methods RequestFactory needs for every entity, plus the service methods.
The persistence here is an in-memory BookStore; with JPA the service methods would use an EntityManager (see Spring Data JPA for the server side).
public class BookEntity {
private Long id;
private Integer version = 0;
@NotNull
@Size(min = 1, max = 200, message = "The title must have between 1 and 200 characters")
private String title;
@NotNull
private String author;
private int year;
private Publisher publisher;
public BookEntity() {} // create
public Long getId() { return id; } // getId
public Integer getVersion() { return version; } // getVersion
public static BookEntity findBookEntity(Long id) { // find: "find" + simple class name
return BookStore.INSTANCE.find(id);
}
public static Long countBooks() { return BookStore.INSTANCE.count(); }
public static List<BookEntity> findBookEntries(int firstResult, int maxResults) {
return BookStore.INSTANCE.page(firstResult, maxResults);
}
public static BookEntity findBook(Long id) { return findBookEntity(id); }
public void persist() { BookStore.INSTANCE.save(this); }
public void remove() {
requireRole("librarian");
BookStore.INSTANCE.remove(id);
}
private static void requireRole(String role) {
HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
if (request == null || !request.isUserInRole(role)) {
throw new SecurityException("Not allowed");
}
}
// getters and setters omitted
}
| Purpose | In the entity | In a Locator<T, I> |
|---|---|---|
Create a new instance |
A public no-argument constructor |
|
Get the id |
|
|
Find by id |
A static method named "find" plus the simple class name, with the id as only parameter: |
|
Get the version |
|
|
The Developer Guide table lists those four. The abstract Locator class in 2.13.1 also declares getDomainType() and getIdType(), which a concrete locator must implement, and a non-abstract isLive(T) that calls find.
The version is how RequestFactory detects changes: the server answers each call with the entities whose version changed, and the client fires EntityProxyChange events for them.
Measured: after persist() of the edited book the stored version went from 1 to 2, and the next load returned "version":2.
remove() checks the role on the server. The check is a servlet-container check on the thread-local request. Never rely on a client to hide a button: every service method that changes state or returns sensitive data needs its own server-side authorisation.
An entity without persistence code: Locator and ServiceLocator
When the domain class should stay free of persistence code, or several entities share one DAO, a Locator supplies the four methods and a ServiceLocator supplies the service instance.
The Bookshelf ReviewEntity is such a class.
@ProxyForName(
value = "com.example.bookshelf.server.rf.ReviewEntity",
locator = "com.example.bookshelf.server.rf.ReviewLocator")
public interface ReviewProxy extends EntityProxy {
Long getId();
Long getBookId();
void setBookId(Long bookId);
int getStars();
void setStars(int stars);
String getComment();
void setComment(String comment);
}
@ServiceName(
value = "com.example.bookshelf.server.rf.ReviewService",
locator = "com.example.bookshelf.server.rf.ReviewServiceLocator")
public interface ReviewRequest extends RequestContext {
Request<List<ReviewProxy>> reviewsFor(Long bookId);
Request<Void> save(ReviewProxy review);
}
public class ReviewLocator extends Locator<ReviewEntity, Long> {
@Override public ReviewEntity create(Class<? extends ReviewEntity> clazz) { return new ReviewEntity(); }
@Override public ReviewEntity find(Class<? extends ReviewEntity> clazz, Long id) { return ReviewService.REVIEWS.get(id); }
@Override public Class<ReviewEntity> getDomainType() { return ReviewEntity.class; }
@Override public Long getId(ReviewEntity domainObject) { return domainObject.getId(); }
@Override public Class<Long> getIdType() { return Long.class; }
@Override public Object getVersion(ReviewEntity domainObject) { return domainObject.getVersionNumber(); }
}
public class ReviewServiceLocator implements ServiceLocator {
private static final ReviewService SERVICE = new ReviewService();
@Override
public Object getInstance(Class<?> clazz) {
if (clazz != ReviewService.class) {
throw new IllegalArgumentException("Unknown service");
}
return SERVICE;
}
}
public class ReviewService {
static final Map<Long, ReviewEntity> REVIEWS = new ConcurrentSkipListMap<>();
public List<ReviewEntity> reviewsFor(Long bookId) { /* filter REVIEWS */ }
public void save(ReviewEntity review) { /* validate stars 1..5, assign an id, store */ }
}
The locator and the service locator need public no-argument constructors, and RequestFactory caches both and the service instance, so they must be thread-safe (Developer Guide).
ValueLocator is a convenience subclass of Locator for value types: it fixes the identity methods to return null.
Because the service is an instance, save(ReviewProxy) takes the proxy as an ordinary argument instead of using().
The run saved a review of book 1 and read it back; the ServiceLocator was used for both calls.
Calling it from the client
Creating, editing and persisting
BookRequest ctx = factory.bookRequest();
BookProxy book = ctx.create(BookProxy.class); // a new, client-owned proxy
book.setTitle("Refactoring");
book.setAuthor("Martin Fowler");
book.setYear(1999);
PublisherProxy publisher = ctx.create(PublisherProxy.class);
publisher.setName("Addison-Wesley");
publisher.setCountry("US");
book.setPublisher(publisher);
ctx.persist().using(book).fire(new Receiver<Void>() {
@Override
public void onSuccess(Void ignored) { /* refresh the view */ }
});
Proxies are interfaces and have no constructor, so a new one is created with ctx.create(BookProxy.class) on the context that will send it.
The entity and its publisher are created in the same context, so they travel together: RequestFactory sends the whole graph of one context in a single request.
Whether the server saves the related object depends on the server code; the guide says the implementation of persist() is responsible for persisting related objects.
Objects that did not come from create must be made editable with edit(), in the context that will send them. The editable copy replaces the original, which can be discarded.
Properties returned by the getters of an editable proxy are editable too.
What goes over the wire
The payload of the create above and of the edit that follows are shown below, as printed by the transport wrapper of the test.
The type tokens and operation tokens are 28-character base64 digests derived from the interface and method names; they are replaced here by BOOK_PROXY_TYPE_TOKEN, PUBLISHER_PROXY_TYPE_TOKEN, PERSIST_OPERATION and FIND_BOOK_OPERATION.
>>> {"F":"com.example.bookshelf.shared.rf.BookshelfRequestFactory",
"I":[{"P":[{"R":"1","C":1,"T":"BOOK_PROXY_TYPE_TOKEN"}],"O":"PERSIST_OPERATION"}],
"O":[{"P":{"year":1999,"author":"Martin Fowler","publisher":{"R":"1","C":2,"T":"PUBLISHER_PROXY_TYPE_TOKEN"},"title":"Refactoring"},
"R":"1","C":1,"T":"BOOK_PROXY_TYPE_TOKEN","O":"PERSIST"},
{"P":{"country":"US","name":"Addison-Wesley"},"R":"1","C":2,"T":"PUBLISHER_PROXY_TYPE_TOKEN","O":"PERSIST"}]}
<<< {"S":[true],"I":[null],
"O":[{"C":1,"S":"IjQi","T":"BOOK_PROXY_TYPE_TOKEN","V":"MS4w","O":"PERSIST"},
{"R":"1","C":2,"T":"PUBLISHER_PROXY_TYPE_TOKEN"}]}
>>> {"F":"com.example.bookshelf.shared.rf.BookshelfRequestFactory",
"I":[{"P":[{"S":"IjQi","T":"BOOK_PROXY_TYPE_TOKEN"}],"O":"PERSIST_OPERATION"}],
"O":[{"P":{"year":2018},"S":"IjQi","T":"BOOK_PROXY_TYPE_TOKEN","V":"MS4w","O":"UPDATE"}]}
<<< {"S":[true],"I":[null],"O":[{"S":"IjQi","T":"BOOK_PROXY_TYPE_TOKEN","V":"Mi4w","O":"UPDATE"}]}
The names are defined by annotated interfaces in the messages package, which are AutoBeans themselves:
| Key | Meaning |
|---|---|
|
The name of the |
|
Invocations: one object per service call, with |
|
Operations: the creates and edits of proxies, with |
|
Type token, client id, server id, version, synthetic id. |
|
Strength of the id: |
|
A status per invocation: |
|
Violations (see below); also the exception type inside a failure object |
|
A general failure; inside a failure object |
Two properties follow from the wire format. First, the edit sent "P":{"year":2018} only, not the other properties of the book: that is the delta behaviour the guide advertises, and the client test asserts it.
Second, the server never calls a method by name. The operation token must be one the build-time validation recorded in the generated lookup class, so a request for any other method is rejected with No RequestContext for operation ... (see the pitfalls).
That makes the payload a whitelist of the operations the interfaces declare, not a way to run arbitrary methods. It does not make it a substitute for authorisation.
Receivers, failures and violations
Receiver<V> is an abstract class. onSuccess is abstract; onFailure(ServerFailure) throws a RuntimeException for a fatal failure unless you override it; onConstraintViolation(Set<ConstraintViolation<?>>) is the current way to receive validation errors, and onViolation(Set<Violation>) and the Violation interface are deprecated in 2.13.1.
ctx.persist().using(book).fire(new Receiver<Void>() {
@Override public void onSuccess(Void v) { /* ... */ }
@Override public void onFailure(ServerFailure f) {
showError(f.getMessage()); // never f.getStackTraceString() in the UI
}
@Override public void onConstraintViolation(Set<ConstraintViolation<?>> violations) {
for (ConstraintViolation<?> v : violations) {
showFieldError(v.getPropertyPath().toString(), v.getMessage());
}
}
});
Measured outputs:
| Call | Outcome |
|---|---|
|
|
The same call with a |
|
|
|
The same, with a servlet whose processor has a custom |
|
The default handler (DefaultExceptionHandler) builds the message as "Server Error: " plus the exception message, so a message such as a SQL error or a path would be shown to the user. Provide an ExceptionHandler to new SimpleRequestProcessor(...) or to the servlet constructor RequestFactoryServlet(ExceptionHandler, ServiceLayerDecorator...) that logs the exception and returns a generic message.
Validation on the server
Before calling a method, RequestFactory validates the entities of the request with a JSR-303 (Bean Validation 1.0) provider found with Validation.byDefaultProvider().configure().
The relevant class is ReflectiveServiceLayer.
-
RequestFactory 2.13.1 uses the
javax.validationnamespace. A provider in thejakarta.validationnamespace (Hibernate Validator 7 and later) is not seen by it; Validation describes how to keep constraints for both namespaces. -
If no provider can be created,
ValidationExceptionis caught and logged at INFO ("Unable to initialize a JSR 303 Bean Validator") and no validation happens. Any otherErrorfrom the provider’s start-up is not caught. -
The system property
gwt.validation.ignoreXml=truemakes the server skipvalidation.xml. With Hibernate Validator 4.1.0.Final on JDK 21 the start-up fails without it because the provider needs JAXB (see the pitfalls). Validation has the details of the property for compile, test and code server runs.
See Validation for the client-side validation framework and for sharing constraints, and Editors for RequestFactoryEditorDriver, which edits a proxy graph and shows the violations next to the fields.
Events, batching and saving proxies
Every time the client sees an entity for the first time or sees its version change, the factory fires an EntityProxyChange on the EventBus given to initialize.
A handler registers per proxy type:
EntityProxyChange.registerForProxyType(factory.getEventBus(), BookProxy.class,
new EntityProxyChange.Handler<BookProxy>() {
@Override
public void onProxyChange(EntityProxyChange<BookProxy> event) {
refresh(event.getProxyId(), event.getWriteOperation()); // PERSIST, UPDATE or DELETE
}
});
In the run, loading book 2 and then persisting a change to it produced two events, both UPDATE BookProxy: the first when the entity was first received, the second when its version changed.
Two contexts can be sent together with append. The run sent countBooks() and reviewsFor(1L) of two services in one HTTP request:
BookRequest books = factory.bookRequest();
ReviewRequest reviews = books.append(factory.reviewRequest());
books.countBooks().to(countReceiver);
reviews.reviewsFor(1L).to(reviewsReceiver);
books.fire();
>>> {"F":"com.example.bookshelf.shared.rf.BookshelfRequestFactory","I":[{"O":"COUNT_BOOKS_OPERATION"},{"P":["1"],"O":"REVIEWS_FOR_OPERATION"}]}
<<< {"S":[true,true],"I":["3",[]]}
Source: GWT — RequestContext (Javadoc)
RequestBatcher (in requestfactory.gwt.client) automates this: get() returns the open context and schedules the fire at the end of the current event loop turn.
Request.fire() on a context that is already in flight throws IllegalStateException: A request is already in progress.
Transport, security and CSRF
DefaultRequestTransport POSTs the payload with RequestBuilder to the host page base URL followed by gwtRequest, with Content-Type: application/json; charset=utf-8 and two extra headers (pageurl and the permutation strong name).
Change the URL with setRequestUrl, or replace the transport, which is also how to add headers.
The servlet insists on the content type: a request with Content-Type: text/plain returned HTTP 500 with jakarta.servlet.ServletException: Content-Type was 'text/plain'. Expected 'application/json'. A cross-site HTML form cannot set that content type, and a cross-site script needs a CORS preflight to send it, which is a useful barrier but not a CSRF defence you should rely on alone (CORS explains the preflight). GWT’s RPC token mechanism (RpcToken, XsrfProtectedService) does not apply to RequestFactory; XSRF, RPC & Server Security describes the RPC side.
The Bookshelf adds a per-session token that the page gives to the client (for example in a dynamic host page) and that a filter checks on every POST to /gwtRequest:
public class CsrfRequestTransport extends DefaultRequestTransport {
private final String token;
public CsrfRequestTransport(String token) { this.token = token; }
@Override
protected void configureRequestBuilder(RequestBuilder builder) {
super.configureRequestBuilder(builder);
builder.setHeader("X-Bookshelf-Csrf", token);
}
}
// server: servlet filter mapped to /gwtRequest and /csrf
String sent = request.getHeader("X-Bookshelf-Csrf");
if (sent == null || !MessageDigest.isEqual(sent.getBytes(), token.getBytes())) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
chain.doFilter(req, resp);
The filter is application code, not part of GWT. Measured: GET /csrf with a new session returned a 32-character token and a JSESSIONID cookie; a POST without the header returned 403; with the header it returned 200 and the JSON response.
The token is the one placeholder-style value used here; the real one is random per session.
Other points for a RequestFactory endpoint:
-
Authentication and authorisation belong on the server. Protect
/gwtRequestwith the container’s security constraints or a filter, and check roles in the service methods asremove()does. The proxies tell the client what may be requested, not what may be done. -
Expose only what the client needs. The proxy is the whitelist of properties the client can read and write, and every property of it travels whenever the entity is returned. The Developer Guide’s own
EmployeeProxydeclaresgetPassword(); do not copy that. Keep password hashes, internal flags and other users' data out of proxies, and never map a JPA entity directly to a proxy without choosing its properties. -
No built-in limit on the request. In the run a 2 MB body was handed to the processor and failed only because its factory name (
x) could not be resolved (HTTP 500,Could not locate class xin the log). Set a body-size limit in the container or a filter. An open GitHub issue, gwtproject/gwt#10385 (opened 2026-07-31, labelledNeedsInfoand still under discussion on 2026-10-09), reports thatSimpleRequestProcessorapplies no bound to the number of operations and invocations in one request; until that is settled, limit the size at the edge. -
Exception messages reach the browser (see the previous section).
-
Log what you need on the server and keep stack traces out of the response, which is the default.
The validation tool: requestfactory-apt
The server finds out what the client interfaces mean from a class that is generated at build time, not by reflection over the proxies.
The class is called <RequestFactory interface>DeobfuscatorBuilder (for the Bookshelf, com.example.bookshelf.shared.rf.BookshelfRequestFactoryDeobfuscatorBuilder) and is produced by RfValidator, the annotation processor in requestfactory-apt.
It checks that every proxy property and every context method has a counterpart on the domain classes and the services, then writes the lookup of operation tokens, type tokens and the client-to-domain mapping.
If the class does not exist at run time the server cannot process any request.
The Developer Guide does not mention it. The 2.4.0 release notes mention a "RequestFactoryInterfaceValidator" that is not enabled by default and point to a wiki page; the usage text of the tool still prints an address of that wiki on the retired code.google.com project hosting, which now redirects to the Google Code Archive.
There are two ways to run it.
As an annotation processor in the module that sees both the interfaces and the domain classes. The Bookshelf interfaces are in bookshelf-shared but the domain classes are in bookshelf-server, so the processor runs when bookshelf-server compiles, with the rootOverride option naming the factory to scan (the processor otherwise scans only the sources of the compilation):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.gwtproject.web.bindery</groupId>
<artifactId>requestfactory-apt</artifactId>
<version>2.13.1</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-ArootOverride=com.example.bookshelf.shared.rf.BookshelfRequestFactory</arg>
</compilerArgs>
</configuration>
</plugin>
The processor’s supported options are rootOverride (a comma-separated list of binary names), suppressErrors, suppressWarnings and verbose.
After the build the generated class was in target/classes and in target/test-classes (the test compilation runs the processor too).
As a command-line tool on compiled classes. ValidationTool takes an output directory or jar and the factory names:
java -cp requestfactory-apt-2.13.1.jar:requestfactory-client-2.13.1.jar:bookshelf-server/target/classes:bookshelf-shared/target/classes:validation-api-1.0.0.GA.jar \
com.google.web.bindery.requestfactory.apt.ValidationTool /tmp/rf-validated.jar \
com.example.bookshelf.shared.rf.BookshelfRequestFactory
It exited with 0 and the jar contained BookshelfRequestFactoryDeobfuscatorBuilder.class. With -client as first argument it generates the ...DeobfuscatorBuilderLite class, for clients that run on a JVM without the domain classes.
The tool needs a JDK, not a JRE.
Source: GWT — ValidationTool (Javadoc)
What the validation reports, measured by adding a bad property and bad methods to the Bookshelf interfaces:
[ERROR] Could not find domain method similar to java.lang.String missing()
[ERROR] Could not find domain method similar to java.lang.Long countBooks(java.lang.String)
[ERROR] Could not find domain method similar to java.lang.String getIsbn()
[ERROR] Domain type com.example.bookshelf.server.rf.Publisher does not have a getId() method
[ERROR] Domain type com.example.bookshelf.server.rf.Publisher does not have a getVersion() method
The last two appear when PublisherProxy is changed from ValueProxy to EntityProxy: an entity needs an id and a version on the domain type.
The processor failed the Maven build for the server module, so the mismatch is found at build time, not by the first user.
@SkipInterfaceValidation (on a method, type or package) excludes a declaration from the check; use it sparingly because it removes the guarantee.
A GitHub issue reports that the processor fails with Java records in client code (gwtproject/gwt#10114, opened 2025-04-11, still open on 2026-10-09).
The Bookshelf worked example
The scratch application is the three-module Bookshelf of Project Structure & Modules with the files below added.
| File | Content |
|---|---|
|
|
|
|
|
|
|
The two |
|
|
|
The filter and the |
|
Eight JUnit tests running the real client and server in one JVM |
|
|
The commands used, from the root of the scratch application (JDK 21):
# server tests: the real client and server in one JVM, plus the AutoBean tests
mvn -B -pl bookshelf-server -am test -Dtest='BookRequestFactoryTest,AutoBeanJvmTest' \
-Dsurefire.failIfNoSpecifiedTests=false -DargLine="-Dgwt.validation.ignoreXml=true"
# generated client and AutoBeans in HtmlUnit, then the full production compile
mvn -B -pl bookshelf-client -am verify -Dtest=RfGwtTest -Dsurefire.failIfNoSpecifiedTests=false
# the servlet on port 8935 (the property is for the Maven JVM that runs Jetty)
MAVEN_OPTS="-Dgwt.validation.ignoreXml=true" mvn -B -pl bookshelf-server -am -Denv=dev \
-DskipTests package jetty:run -Djetty.http.port=8935
Source: gwt-maven-plugin documentation
Results: 17 server-side tests passed (9 AutoBean, 8 RequestFactory), the 3 GWTTestCase tests passed, and the 6-permutation production compile of the whole application succeeded.
The server-side tests use no HTTP:
RequestTransport inner =
new InProcessRequestTransport(new SimpleRequestProcessor(ServiceLayer.create()));
BookshelfRequestFactory rf = RequestFactorySource.create(BookshelfRequestFactory.class);
rf.initialize(new SimpleEventBus(), inner);
The client test replaces the transport by one that records what the generated client sends and answers with a payload that the real servlet returned:
static class Replay implements RequestTransport {
final List<String> sent = new ArrayList<String>();
final List<String> replies = new ArrayList<String>();
@Override
public void send(String payload, TransportReceiver receiver) {
sent.add(payload);
receiver.onTransportSuccess(replies.remove(0));
}
}
In HtmlUnit the generated client sent the payload below for load(0, 1, ...) and, after changeYear, a payload containing "P":{"year":2018}. The operation and type tokens computed by the generated JavaScript client were identical to those the JVM client and the server computed; the key order differs only in that the browser writes "O" before "P".
{"F":"com.example.bookshelf.shared.rf.BookshelfRequestFactory","I":[{"O":"FIND_BOOK_ENTRIES_OPERATION","P":[0,1],"R":["publisher"]}]}
The HTTP side was driven with curl against Jetty:
TOKEN=$(curl -s -c cookies.txt http://localhost:8935/csrf)
curl -s -b cookies.txt -H 'Content-Type: application/json; charset=utf-8' -H "X-Bookshelf-Csrf: $TOKEN" \
-d '{"F":"com.example.bookshelf.shared.rf.BookshelfRequestFactory","I":[{"P":[0,2],"O":"FIND_BOOK_ENTRIES_OPERATION"}]}' \
http://localhost:8935/gwtRequest
Source: GWT — Request Factory: Wiring
The response was HTTP 200, Content-Type: application/json;charset=utf-8, with the two first books. A second persist and the validation failure behaved as in the in-process tests.
The full application (6 permutations) also compiled with RequestFactory and AutoBeans inherited.
AutoBeans
AutoBeans are the framework RequestFactory is built on, and they are useful on their own: the Developer Guide describes them as automatically generated implementations of bean-like interfaces plus a low-level serialisation mechanism for them. The goals it lists are less boilerplate in model-rich applications, easy encoding to JSON, support code for common operations on data-model objects, and use in non-GWT code such as a server. Its non-goals are non-DAG data structures and object-identity semantics.
Interfaces, a factory and the codex
public interface BookMeta {
String getTitle();
void setTitle(String title);
List<String> getAuthors();
void setAuthors(List<String> authors);
@PropertyName("first_published")
int getFirstPublished();
@PropertyName("first_published")
void setFirstPublished(int year);
PublisherMeta getPublisher();
void setPublisher(PublisherMeta publisher);
Map<String, String> getTags();
void setTags(Map<String, String> tags);
}
public interface PublisherMeta {
String getName();
void setName(String name);
String getCity();
void setCity(String city);
}
public interface MetaFactory extends AutoBeanFactory {
AutoBean<BookMeta> bookMeta();
AutoBean<PublisherMeta> publisherMeta();
AutoBean<PublisherMeta> publisherMeta(PublisherMeta toWrap); // wraps an existing object
}
MetaFactory factory = GWT.create(MetaFactory.class); // JVM: AutoBeanFactorySource.create(MetaFactory.class)
AutoBean<BookMeta> bean = AutoBeanCodex.decode(factory, BookMeta.class, json);
BookMeta book = bean.as(); // the interface shim
book.setTitle("Clean Code, 2nd draft");
String out = AutoBeanCodex.encode(bean).getPayload(); // back to JSON
Source: GWT — AutoBeans: Quickstart
Input and output of the run (JVM; the same encode in the browser engine produced the same members in a different order):
{"title":"Clean Code","authors":["Robert C. Martin"],"first_published":2008,"publisher":{"name":"Prentice Hall","city":"Upper Saddle River"},"tags":{"genre":"programming"},"unknown":true}
{"publisher":{"city":"Upper Saddle River","name":"Prentice Hall"},"title":"Clean Code, 2nd draft","first_published":2008,"authors":["Robert C. Martin"],"tags":{"genre":"programming"}}
Unknown members of the input ("unknown":true) are ignored on decode and not written again (they remain visible through a Splittable).
The name of a property in JSON is the Java Beans name, with @PropertyName overriding it on a getter, a setter, a method parameter or an enum constant.
| Type | What it does |
|---|---|
|
The controller of a bean. |
|
Interface with methods that return |
|
A category implements non-property methods; |
|
|
|
The wire value: backed by a |
|
|
|
Reflection-like traversal: |
|
JVM only: |
The property types the Developer Guide allows are primitives and boxed primitives, BigInteger, BigDecimal, java.util.Date, enums, String, other bean interfaces, and List, Set and Map of those.
What the run showed
frozen: java.lang.IllegalStateException: The AutoBean has been frozen
tag: cache, in payload? false
clone: java.lang.UnsupportedOperationException
isWrapper=true pojo.name=Pearson unwrap==pojo true json={"city":"Upper Saddle River","name":"Pearson"}
after unwrap: java.lang.IllegalStateException: The AutoBean has been unwrapped
splittable: kind=book title=Clean Code keys=[publisher, title, first_published, authors, tags, unknown]
category: Book: Refactoring
diff: {publisher={"city":"Upper Saddle River","name":"Prentice Hall"}, title=Clean Code 2, first_published=2009, tags=...SplittableSimpleMap@23bb8443}
all: [publisher, title, first_published, authors, tags]
ref publisher -> PublisherMeta
value name=Prentice Hall (String)
collection authors of String
map tags String->String
-
setFrozen(true)makes every setter throwIllegalStateException: The AutoBean has been frozen. Proxies received from RequestFactory are frozen in the same way untiledit(). -
Tags are metadata kept beside the bean (
setTag/getTag); they are not part of the JSON. -
clone(boolean)is deprecated with no replacement and throwsUnsupportedOperationException, although the Developer Guide still lists it. Copy by encoding and decoding, or withdecodeInto. -
Wrapping (
factory.publisherMeta(pojo)) makes the AutoBean a controller around an existing object: a setter on the shim changed the POJO. Afterunwrap()the AutoBean is unusable. -
Splittableproperties delay decoding. The envelopeShelfhas aSplittable payload; the receiver readskind, picks the factory for the payload and callsAutoBeanCodex.decode(factory, BookMeta.class, payload). -
Categories give implementations to methods that are not getters or setters. A bean with such a method needs the factory annotated
@Category(DescribableCategory.class), and the category has a public static method of the same name with theAutoBeanas extra first parameter. According to the guide, a category may also declare a method named__intercept(AutoBean<?>, T)that sees the return value of every non-void method, and RequestFactory uses it to make proxies returned from an editable object editable (this was not run here). -
AutoBeanVisitorvisited the reference property, then the value properties of the nested bean, then the collection and the map, with the element and key types. -
diffis shallow and compares references. It reportedpublisherandtagsas changed although onlytitleandfirst_publishedwere; in the browser engine it printed[publisher, title, tags]. Compare nested values yourself or usedeepEquals. -
deepEqualsdiffers between the JVM and the browser engine for maps. Two beans decoded from the same JSON with aMapproperty weredeepEqualsfalse on the JVM and true in HtmlUnit; with only value, list or nested-bean properties it was true in both. Do not depend on it for maps.
Errors on bad input
JVM: java.lang.RuntimeException: Could not parse payload
Browser: java.lang.IllegalArgumentException: Error parsing JSON: SyntaxError: Empty JSON string
JVM: java.lang.NullPointerException: Cannot invoke "java.lang.Double.doubleValue()" because "this.number" is null (for "first_published":"abc")
Browser: 0 (the same input)
Decoding is not strict: a string where a number is expected gave a NullPointerException on the JVM and 0 in the browser engine, both without a message that names the property.
Validate untrusted JSON (size, depth, ranges) before relying on the decoded values, and wrap decoding in a try/catch (RuntimeException).
Where AutoBeans fit
| Option | Good for | Costs |
|---|---|---|
AutoBeans |
Typed JSON on both client and server with one set of interfaces; shared models; RequestFactory |
Generated code per factory and type; interfaces cannot have extra fields; limited error messages (above) |
Overlay types or JsInterop native types |
Reading a JSON document without copying it |
Client only; no server counterpart; see RequestBuilder, JSON & XML |
|
Small payloads and J2CL-friendly code |
Client only |
A server JSON library (Jackson, Gson) with GWT-compatible DTOs |
The server side of a REST API |
The client needs another mechanism; see REST & JSON Libraries |
RequestBuilder, JSON & XML describes JsonUtils, JSONParser, overlay types and JsInterop DTOs, and REST & JSON Libraries describes the libraries that generate the client; AutoBeans are the option that needs only GWT.
Pitfalls
| Symptom | Cause | Fix |
|---|---|---|
Server: |
The |
Add |
Build: |
The proxy declares a property that the domain class has no getter for |
Add the property to the domain class or remove it from the proxy |
Build: |
A context method has no static or instance method with the same name and parameters (domain types in place of proxies) |
Add the server method with the mapped signature |
Build: |
An |
Make it a |
Server log: |
The entity has no finder named "find" plus its simple class name ( |
Add the finder or a |
GWT compile: |
The module with the shared sources does not inherit |
Add the |
Jetty: |
The |
Use |
Jetty plugin warnings: |
|
Keep one of them |
HTTP 500, |
A client or test posts with another content type |
Send |
HTTP 500 and the log |
The operation token is not in the generated lookup (an old client, a different interface version, or a request that was not built by RequestFactory) |
Redeploy client and server together; the token changes when names change |
Server start-up: |
Hibernate Validator 4.1 reads |
|
|
The |
Override |
|
The proxy came from the server and was not passed to |
Call |
|
|
Create a new context per request |
|
A proxy created or edited in one context was used in another |
Edit or create the proxy in the context that will send it |
The browser shows |
|
Provide an |
|
The method is deprecated with no replacement |
Encode and decode, or use |
Maintenance status and when not to start new code with it
What is verified (2026-10-09):
-
Published and built. The 2.13.1 BOM imports the
requestfactorypom;requestfactory-clienthas been released for every version from 2.10.0 to 2.13.1 underorg.gwtproject.web.bindery(Maven Central metadata, last updated 2026-06-19), the-server,-server-jakartaand-aptjars of 2.13.1 were downloaded and inspected, and the Jakarta artifacts were added in 2.11.0. The 2.12.0 release notes list the removal of theRequestFactoryJarExtractorclass from the release jars. -
Not deprecated.
RequestFactory,RequestContext,EntityProxy,ValueProxy,Locatorand the annotations carry no@Deprecatedin the 2.13.1 source. The deprecated members areReceiver.onViolation,Violation,RequestFactoryEditorDriver.setViolations,AutoBean.cloneandValueCodex.decode(Class, String). -
No official notice. The Developer Guide page, the release notes and the roadmap contain no statement that RequestFactory is deprecated or in maintenance mode, and none was found elsewhere on gwtproject.org. The roadmap does not mention it at all. This page therefore does not claim any official status.
-
Activity is housekeeping and small fixes. Eleven commits touched the
requestfactorysource directory between 2024-01-01 and 2026-10-09: formatting, Checkstyle, Javadoc, the Java 17 language level (2026-06-24), removal of deprecated or internal types, and makingjaxboptional for the validation tests. Fixes in the AutoBean code in that period are for Java 21 (aList<Integer>property inProxyAutoBean, 2024-01-31), a bytecode size limit ininitializeEnumMap()(2024-07-16), and thread-safe date parsing inStringQuoter(gwtproject/gwt#10322, 2026-06-25). The last change toSimpleRequestProcessor.javathat GitHub lists is from 2013-10-18. -
Open issues. Among others: #10385 (no bound on operations and invocations), #10114 (
requestfactory-aptfails with records), #9686 (the JSR-303 layer on Java 9 and later, opened 2020) and #9289 (default methods on proxies). -
The Developer Guide is old. It describes the 2.1 design, still shows
javaxand theonViolationcallback, says "in future articles" about cell widgets and Editors, and does not mention the build-time validation.
What is not verified: there is no statement from the GWT steering committee on the future of RequestFactory, and this page does not repeat the common claim that it is in maintenance mode.
An opinion, not an official position, but each point follows from the facts above:
-
Do not start new code with it unless you need its model. The model (entities with identity, deltas,
EntityProxyChangeevents, joined contexts) is what you would be buying. If you need only to read and write JSON, GWT-RPC (for a GWT-only client and server) or plain JSON over HTTP with a typed client (for a client that other consumers share) is simpler, and a JSON API can be used by tools, tests and non-GWT clients. -
It binds you to GWT on the server. The protocol is a private format whose only specification is the source, and the servlet is not a place for a Spring Boot or Quarkus controller; a REST backend can be reused, a
RequestFactoryServletcannot. -
It binds you to old validation. JSR-303 in the
javaxnamespace is what 2.13.1 reads; the rest of the Java ecosystem has moved tojakarta.validation. -
The tooling is brittle. A forgotten annotation processor fails at the first request, not at the build, and a records issue is open.
-
The documentation is thin. Anything beyond the Developer Guide is found in the source.
-
Keep it where it already runs. An existing application that works needs no urgent change; plan a replacement when the model no longer fits or when the validation namespace or the servlet container forces the issue.
Use RequestFactory for a new project only when most of this is true: the application is GWT-only on both sides, the data is naturally a graph of entities with versions, you will use the EventBus change events and joined contexts, the team already knows it, and a documented REST API is not a requirement.
Otherwise use the options on Client–Server Communication, GWT-RPC, RequestBuilder, JSON & XML and REST & JSON Libraries.
Where older material is outdated
-
GWT in Action (Manning, 2007) was written for GWT 1.3 and 1.4. RequestFactory appeared with GWT 2.1 (the Developer Guide calls it the heart of the "Bindery" features of 2.1, and the 2.1.0 release candidate notes already list fixes for it) and the AutoBeans guide refers to 2.1.1 and 2.2, so the book has no coverage of either (its extracted text contains neither name); its data-transfer chapters concern GWT-RPC, which is what the first edition recommends.
-
The Developer Guide’s
web.xmluses thejavaxservlet class; for Servlet 5 or 6 use thejakartaclass (since 2.11.0). -
The guide’s dependency list names
requestfactory-server.jarand avalidator-api-1.0.0.GA.jar; in Maven the artifacts areorg.gwtproject.web.bindery:requestfactory-server(-jakarta)orgwt-servlet(-jakarta), andjavax.validation:validation-api. -
The guide uses
Receiver.onViolation; useonConstraintViolation. -
The guide’s
Locatortable lists four methods; the abstract class also requiresgetDomainType()andgetIdType(). -
The AutoBeans guide lists
clone(); it throwsUnsupportedOperationExceptionand is deprecated. It says thatAutoBeanFactorySourcewas calledAutoBeanFactoryMagicin 2.1.1 and 2.2 (its text mentionsAutoBeanMagicSource, which is a slip); the class in 2.13.1 isAutoBeanFactorySource. -
The tool’s own usage text points to a wiki page on the retired
code.google.comhosting (now in the Google Code Archive).
What changed recently
-
2.1.0 (RC1 notes): the first RequestFactory fixes; 2.1.1: a service layer added to RequestFactory (#5111).
-
2.4.0: polymorphism (#5367), service inheritance on the client (#6234),
RequestFactoryEditorDriverwork (#6081), more compact type tokens (#5394), and the interface validation tooling. -
2.6.0 (RC1 notes): Map support, enums as type parameters,
EntityProxyIdas a request parameter. 2.7.0 (RC1 notes): better handling of overridden methods and generics,@SkipInterfaceValidationon context methods. -
2.11.0 (2024-01-09):
requestfactory-server-jakartaandgwt-servlet-jakarta. -
2.12.0:
RequestFactoryJarExtractorno longer included in release jars. -
2.13.0 (2026-02-11): JAXB and
xml-apisoptional whengwt.validation.ignoreXmlis set (Validation). -
2.13.1 (2026-06-19): latest release.
References
-
GWT — Release notes (2.1.0, 2.1.1, 2.3.0, 2.4.0, 2.11.0, 2.12.0, 2.13.0)
-
GWT 2.13.1 source — ReflectiveServiceLayer.java (validation)
-
GWT 2.13.1 source — Deobfuscator.java (ValidationTool message)
-
GWT issue 10385 — bound the operation and invocation counts in a RequestFactory request
-
GWT issue 10114 — requestfactory-apt fails with records in client code
-
Robert Hanson and Adam Tacy, GWT in Action (Manning, 2007), consulted only for outdated notes