My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
AutoBean  
Structure, not boilerplate
Updated May 21, 2012 by kurka.da...@gmail.com

GWT AutoBean framework

The AutoBean framework provides automatically-generated implementations of bean-like interfaces and a low-level serialization mechanism for those interfaces. AutoBeans can be used in both client and server code to improve code re-use. For example, the Requestfactory system uses AutoBeans extensively in both the client and server code. This document describes the state of AutoBeans as found in the GWT 2.1.1 release onwards.

Goals

  • Decrease boilerplate in model-rich applications
  • Support easy encoding of AutoBeans to JSON structures
  • Provide support code for common operations on data-model objects
  • Usable in non-GWT (e.g. server) code

Non-goals

  • Support for non-DAG datastructures
  • Support for object identity semantics

If higher-order model semantics are needed, the non-goals for AutoBeans are key features of the RequestFactory framework.

Quickstart

// Declare any bean-like interface with matching getters and setters, no base type is necessary
interface Person {
  Address getAddress();
  String getName();
  void setName(String name);
  void setAddress(Address a);
}

interface Address {
  // Other properties, as above
}

// Declare the factory type
interface MyFactory extends AutoBeanFactory {
  AutoBean<Address> address();
  AutoBean<Person> person();
}

class DoSomething() {
  // Instantiate the factory
  MyFactory factory = GWT.create(MyFactory.class);
  // In non-GWT code, use AutoBeanFactorySource.create(MyFactory.class);

  Person makePerson() {
    // Construct the AutoBean
    AutoBean<Person> person = factory.person();

    // Return the Person interface shim
    return person.as();
  }

  String serializeToJson(Person person) {
    // Retrieve the AutoBean controller
    AutoBean<Person> bean = AutoBeanUtils.getAutoBean(person);

    return AutoBeanCodex.encode(bean).getPayload();
  }

  Person deserializeFromJson(String json) {
    AutoBean<Person> bean = AutoBeanCodex.decode(factory, Person.class, json);
    return bean.as();
  }
}

Property types

The following types may be used to compose AutoBean interfaces:

  • Value types:
    • Primitive types and their boxed counterparts
    • BigInteger, BigDecimal
    • java.util.Date
    • enum types
    • Strings
  • Reference types:
    • Bean-like interfaces
    • Lists or Sets of any supported property type
    • Maps of any supported property type

AutoBean

An AutoBean must be parameterized with an interface type (e.g. AutoBean<Person>). This interface type may have any type hierarchy and need not extend any particular type in order to be usable with AutoBeans. A distinction is made as to whether or not the target interface is "simple."

A simple interface satisfies the following properties:

  • Has only getter and setter methods
  • Any non-property methods must be implemented by a category

A simple AutoBean can be constructed by the AutoBeanFactory without providing a delegate instance.

If a reference interface is returned from a method in a target interface, that instance will be automatically wrapped by an AutoBean instance. This behavior can be disabled by placing a @NoWrap annotation on the AutoBeanFactory.

accept()

The AutoBean controller provides a visitor API to allow the properties of an AutoBean to be examined by code that has no prior knowledge of the interface being wrapped.

as()

The AutoBean acts as a controller for a shim object that implements the interface with which the AutoBean is parameterized. For instance, in order to get the Person interface for an AutoBean<Person> it is necessary to call the as() method. The reason for this level of indirection is to avoid any potential for method signature conflicts if the AutoBean were to also implement its target interface.

clone()

An AutoBean and the property values stored within it can be cloned. The clone() method has a boolean parameter that will trigger a deep or a shallow copy. Any tag values associated with the AutoBean will not be cloned. AutoBeans that wrap a delegate object cannot be cloned.

getTag() / setTag()

Arbitrary metadata of any type can be associated with an AutoBean by using the AutoBean as a map-like object. The tag values do not participate in cloning or serialization operations.

isFrozen() / setFrozen()

Property mutations can be disabled by calling setFrozen(). Any attempts to call a setter on a frozen AutoBean will result in an IllegalStateException.

isWrapper() / unwrap()

If the factory method used to instantiate the AutoBean provided a delegate object, the AutoBean can be detached by calling the unwrap() object. The isWrapper() method will indicate

AutoBeanFactory

Instead of requiring a call to GWT.create() for every instance of an AutoBean, only the AutoBeanFactory must be constructed with a call to GWT.create() or AutoBeanFactorySource.create() (in 2.1.1 and 2.2, AutoBeanMagicSource was named AutoBeanFactoryMagic). This allows the AutoBeanFactory to be provided to consuming code by any dependency-injection pattern desired.

Methods in an AutoBeanFactory interface must return AutoBean<Foo>, where Foo is any interface type compatible with AutoBeans. The methods may optionally declare a single parameter of type Foo which allows construction of an AutoBean around an existing object.

interface MyFactory extends AutoBeanFactory {
  // Factory method for a simple AutoBean
  AutoBean<Person> person();

  // Factory method for a non-simple type or to wrap an existing instance
  AutoBean<Person> person(Person toWrap);
}

create()

The create() method accepts a Class object of any interface type reachable from the AutoBeanFactory interface. An optional parameter allows a delegate object to be supplied that will be wrapped by the returned AutoBean.

AutoBeanCodex

The AutoBeanCodex provides general-purpose encoding and decoding of AutoBeans into a JSON-formatted payload.

decode()

This method accepts an AutoBeanFactory, a Class object representing the top-level AutoBean interface type to be returned, and a JSON-formatted payload. The provided AutoBeanFactory must be capable of producing AutoBeans for all interface types reachable from the provided interface.

encode()

This method accepts an AutoBean and returns a Splittable representing a JSON payload that contains the properties of the AutoBean and its associated object graph.

Splittable

The Splittable type is an abstraction around the low-level wire format and library used to manipulate the wire format. For example, in the client-side code Splittable is a JavaScriptObject, while on the server it is backed by the org.json library. The interface offers methods that allow the underlying data model to be queried.

Whenever the AutoBeanCodex encounters a Splittable property or collection of Splittable, the contents returned by the Splittable.getPayload() method will be injected directly into the wire format.

The Splittable type allows message objects backed by different AutoBeanFactory types to combined in a single payload, since the Splittable must be explicitly decoded via AutoBeanCodex.decode().

AutoBeanVisitor

AutoBeanVisitor is a concrete, no-op, base type that is intended to be extended by developers that wish to write reflection-like code over an AutoBean's target interface.

visit() / endVisit()

Regardless of the reference structure of an AutoBean graph, a visitor will visit any given AutoBean exactly once. Users of the AutoBeanVisitor should not need to implement cycle-detection themselves.

As of GWT 2.1.1, the Context interface is empty and exists to allow for future expansion.

visitReferenceProperty() / visitValueProperty()

The property visitation methods in an AutoBeanVisitor type will receive a PropertyContext object that allows the value of the property to be mutated as well as providing type information about the field. Calling the canSet() method before calling set() promotes good code hygiene.

visitCollectionProperty() / visitMapProperty()

These visitation methods behave similarly to visitReferenceProperty() however the PropertyContext passed into these methods is specialized to provide the parameterization of the Collection or Map object.

AutoBeanUtils

diff()

Performs a shallow comparison between the properties in two AutoBeans and returns a map of the properties that are not equal to one another. The beans do not need to be of the same interface type, which allows for a degree of duck-typing.

getAllProperties()

Creates a shallow copy of the properties in the AutoBean. Modifying the structure of the returned map will not have any effect on the state of the AutoBean. The reference values in the map are not cloned, but are the same instances held by the AutoBean's properties.

JSON structures

The AutoBean framework can be used as a JSON interoperability layer to provide a Java typesystem wrapper around an existing JSON api or to create JSON payloads to interact with a remote service. This is accomplished by designing the Java APIs according to the JSON schema. The @PropertyName annotation can be applied to getters and setters where the Java naming convention does not align with the JSON schema.

Generally speaking, the serialized form of an object emitted by AutoBeanCodex mirrors the interface declaration. For instance, the example Person interface described in the quckstart section of this document might be serialized as:

// Whitespace added for clarity
{ "name" : "John Doe", "address" : { "street" : "1234 Maple St", "city" : "Nowhere" } }

List and Set properties are encoded as JSON lists. For example, a List<Person> would be encoded as:

[ { "name" : "John Doe" } , { "name" : "Jim Smith" } ]

Maps are serialized in two forms based on wether or not the key type is a value or reference type. Value maps are encoded as a typical JSON object. For example, a Map<Integer, Foo> would be encoded as

{ "1" : { "property" : "value"}, "55" : { "property" : "value" } }

A map that uses a reference object as a key will instead be encoded as a list of two lists. This allows object-identity maps that contain keys with identical serialized froms to be deserialized correctly. For example, a Map<Person, Address> would be encoded as:

[ [ { "name" : "John Doe" } , { "name" : "Jim Smith" } ] , [ { "street" : "1234 Maple Ave" }, { "street" : "5678 Fair Oaks Lane" } ] ]

Java enum values are written out as the string name of the enum value. This can be overridden by applying the PropertyName annotation to the enum field declaration. The use of names instead of ordinal values will allow the payloads to be robust against endpoint schema skew.

Categories

Pure bean interfaces only go so far to producing a useful system. For example, the EntityProxy type used by RequestFactory is an AutoBean interface, save for the addition of the stableId() method. An AutoBeanFactory can produce non-wrapper (aka "simple") instances of a non-simple interface if an implementation of any non-property interface is provided by a category.

interface Person {
  String getName();
  void setName(String name);
  boolean marry(Person spouse);
}

@Category(PersonCategory.class)
interface MyFactory {
  // Would be illegal without a category providing an implementation of marry(AutoBean<Person> person, Person spouse)
  AutoBean<Person> person();
}

class PersonCategory {
  public static boolean marry(AutoBean<Person> instance, Person spouse) {
    return new Marriage(instance.as(), spouse).accepted();
  }
}

For any non-property method, the category must declare a public, static method which has an additional 0-th parameter which accepts the AutoBean backing the instance. Another example from RequestFactory demonstrating the implementation of the stableId() method:

class EntityProxyCategory {
  EntityProxyId<?> stableId(AutoBean<EntityProxy> instance) {
    return (EntityProxyId<?>) instance.getTag("stableId");
}

The @Category annotation may specify more than one category type. The first method in the first category whose name matches the non-property method that is type-assignable will be selected. The parameterization of the 0-th parameter AutoBean is examined when making this decision.

Interceptors

A category implementation may additionally declare an interceptor method to examine and possible replace the return values of all non-void methods in the target interface:

public static <T> T __intercept(AutoBean<?> bean, T returnValue) {
  // Do stuff
  return maybeAlteredReturnValue;
}

RequestFactory uses this to make EntityProxy objects returned from an editable object editable.

FAQ

Comment by autobean...@gmail.com, Dec 11, 2010

is it possible to use 2.1.1 RequestFactory?/AutoBean to convert POJO to JSON and viceversa when interacting with a RESTful Web Service ?

the common practice with GWT client-server communication is to have packages: client, shared, server, configuring web.xml

however, in-order to be truly loosely coupled, I am thinking of developing the Server side of my app, as a REST WebService?. completely separate from the client. sending JSON encoded data to the Server, and reading JSON.

only using a common .jar file on both containing Entity POJOs.

the problem on GWT client side is a clean way of Converting JSON to POJO back and forth.

I was wondering if the new AutoBean/RequestFactory?/EntityProxy? can help in the situation I described ?

Can i still use "Editor" if I opt for JSON/REST solution above ? What do you think of this approach ? do you think it may result in performance problems ?

I am going to write both the client and servers in Java, and have access to the code. but my main concern is clean separation, complete isolation and loose coupling.

I would like to know what are the down-sides to this, and if the new 2.1.1 features can help ?

these Architectural decisions are about tradeoff, I would like to know what I am going to lose if I chose the approach I described above.

Thank You

Comment by autobean...@gmail.com, Dec 11, 2010

could you please provide a very basic HelloAutoBean? sample in the trunk ?

I have been struggling putting code fragments in this wiki together, but still couldn't get a basic sample to work.

Comment by autobean...@gmail.com, Dec 11, 2010

from the server side of things, how does AutoBean relate to Jackson JSON processor ?

Comment by marius.a...@gmail.com, Dec 12, 2010

Rather than manually declaring interfaces, why not do just

class Person {

String name; Address address;
}

and then have some internal code generators for required AutoBean structures?

See also http://code.google.com/p/google-gson/ which is very easy to use (no boilerplate code), but which doesn't work on GWT due to lack of reflection. I would love AutoBean to work in the same way as gson.

Comment by marius.a...@gmail.com, Dec 12, 2010

There are some mistakes in the sample code:

void setName(String name):
//should be
void setName(String name);

 AutoBean<Person> bean = AutoBeanCodex.decode(myFactory, Person.class, json);
//should be
 AutoBean<Person> bean = AutoBeanCodex.decode(factory, Person.class, json);

Would have been nice to have a full basic working sample, rather than some code made up in a text editor...

Comment by david.nouls, Dec 21, 2010

I have the same question as mr autobeanvonautobahn. The current GWT RPC mechanism is a nightmare for interoperability and also difficult to stress test with tools like JMeter. We want the ability to reuse the RPC calls through a JSON API, with not too much handcoding.

In our product we do not care too much about the potential size difference between RPC and JSON. Performance is still important, but RPC was never very performant (stackoverflow, slow javascript warnings).

So I am thinking about writing a generator that combines the Autobean API with Sync/Async interfaces as used by RPC) ... although I have the impression that comes very close to the RequestFactory? ... but the docs state give me the impression that it is not designed for general rpc method calling, but more for handling JPA,Hibernate stuff.

Comment by project member t.broyer, Dec 21, 2010

RequestFactory? is not designed for an "RPC style" use, but using only ValueProxy? I believe you could do it anyway (it could also be a first step in migrating from GWT-RPC to RF for "CRUD oriented" apps)

Comment by ali.sak...@gmail.com, Mar 7, 2011

Boilerplate, yes boilerplate

What are those interfaces, factories and categories if not boilerplate?! Have you ever looked at Gson?!

Comment by ASolov...@gmail.com, May 18, 2011

AutoBean is likely to be good work out for easy (de)serialization. But why can't it support non-object types? E.g. List<Integer>, List<String>, String which could be serialized as [1,2,3], ["one","two","three"] and simple text correspondingly. Is it planned in further?

Comment by kandula....@gmail.com, Jul 29, 2011

Is there a build configuration change I have to do for using AutoBean API? I'm using gwt-maven-plugin and I see this error when I try to compile my GWT module

ERROR? Errors in 'file:/C:/ccm_wa/Professional/NewsLetter?/NewsLetter?/newsletter/src/main/java/com/conceptis/newsletter/gwt/mailinggroup/client/util/MailFactory?.java'
ERROR? Line 7: No source code is available for type com.google.gwt.autobean.shared.AutoBeanFactory?; did you forget to inherit a required module? ERROR? Line 8: No source code is available for type com.google.gwt.autobean.shared.AutoBean<T>; did you forget to inherit a required module?
ERROR? Errors in 'file:/C:/ccm_wa/Professional/NewsLetter?/NewsLetter?/newsletter/src/main/java/com/conceptis/newsletter/gwt/mailinggroup/client/util/SerializationHelper?.java'
Comment by welt.mic...@gmail.com, Aug 9, 2011

In your project.gwt.xml :

<inherits name="com.google.web.bindery.autobean.AutoBean"/>

should fix the issue

Comment by gabriel....@gmail.com, Aug 17, 2011

Why can't I convert an object that a Map<String,Object>? it throws a null pointer exception and I'm not sure why

Comment by ASolov...@gmail.com, Aug 17, 2011

'Object' type can't be (de)encoded via AutoBean framework. You should read this section again http://code.google.com/p/google-web-toolkit/wiki/AutoBean#Property_types

Comment by gabriel....@gmail.com, Aug 18, 2011

I have another problem and I hope you guys could help me out. I have an interface named BaseValue?

void setValue(String value); void setValues(List<BaseValue> value); String getValue(); List<BaseValue> getValues();

and utils methods such as

int getValueAsInt();

As I have understood, I need to create a class to implement the behavior of such method. public class Value{

public static int getValueAsInt(AutoBean<BaseValue> instance) {
return Integer.parseInt(instance.as().getValue());
}
}

and the factory interface should have @Category(Value.class)

but when I do the folowing I can't get it to work AutoBean<BaseFormData> bean = AutoBeanCodex?.decode(

AutoBeanFactorySource?.create( JSONBeanFactory.class ), BaseFormData?.class, product );
BaseFormData? data = bean.as(); int id = data.getRequest().get( "id" ).getValueAsString(); id is 0. On the other hand data.getRequest().get( "id" ).getValue() returns the correct value Could anyone help me on this?

Thanks a lot guys

Comment by alexpor...@gmail.com, Oct 4, 2011

Regarding Categories:

This is probably loosely implied by the definition of "simple" autobean interfaces, but it may be worth noting that category methods do not seem to work if they begin with the phrase "get", as it seems like it causes the decoder to try and find the matching JSON entity instead of using an implemented category method.

Comment by g...@bloemsma.net, Oct 8, 2011

Is there any way to add logic to AutoBeans??

I don't see a way of overriding accessors. If that is not possible, why bother with them in the first place?

Comment by Ognjen.F...@gmail.com, Oct 25, 2011

Is there a way to specify order of properties in serialized string? For example:

interface JsonRpcRequest {
    String getVersion();
    void setVersion(String version);

    String getMethod();
    void setMethod(String method);

    List<String> getParams();
    void setParams(List<String> params);
}

AutoBeanCodex?.encode(bean).getPayload() serializes using sort order by property name:

    {"method":"method1","params":["param1"],"version":"1.0"}

but what I want is this:

    {"version":"1.0", "method":"method1","params":["param1"]}

Any ideas how to achieve that?

Comment by jasonhall@google.com, Oct 25, 2011

@guus: You can add methods to an AutoBean by using Categories, see allMethods() of http://code.google.com/p/google-apis-explorer/source/browse/trunk/src/com/google/api/explorer/client/base/ApiService.java for example.

@Ognjen.Fabris: I believe the order of JSON keys is designed not to matter, so I don't think that AutoBeans? give you any control over how they are serialized. For what purpose are you trying to serialize in that order? It's possible there's a better way to solve your problem.

Comment by Ognjen.F...@gmail.com, Oct 25, 2011

@jasonhall: You're right! It seems that I was getting timeout during first test with AutoBean request. When I tried with correct order it worked, and assumed that server side takes order into account. But now works in both cases. Thanks!

Comment by Ognjen.F...@gmail.com, Oct 26, 2011

Is it possible to define such interface or other class which would deserialize from string containing array e.g. "["abc","def"]", without property name for the array itself? example:

interface arraySample {
   List<String> getParams();
   void setParams(List<String>);

this interface can be generated from: "{"params":["abc","def"]}". Is there a way to decode List<String> directly from "["abc","def"]", without property name?

Comment by jasonhall@google.com, Oct 26, 2011

I'm not sure what you're asking here. If you're asking about decoding the object you described above without having to name your field getParams(), you can do that using the @PropertyName? annotation, like so:

interface MyObj? {

@PropertyName?("params") List<String> getStuff(); // Note: This is not getParams() !!
}

If you want to decode the string "{'params':['a', 'b']}" directly into a list, you can't do that. You'll need to define the object then get the field like you described above.

I don't believe there's a way to decode the string "['a', 'b']" directly to a List. At least not yet?

Comment by ame...@gmail.com, Nov 2, 2011

How to use it with list of custom Objects. I tried several approaches. Is this supported?

Comment by jasonhall@google.com, Nov 2, 2011

This is supported, yes.

interface Container {
  List<Item> getItems();
}
interface Item {
  String getFoo();
}

This will (de)serialize to:

{
 "items": [
  {
   "foo": "bar"
  },
  {
   "foo": "baz"
  },
  ...
 ]
}
Comment by uhl.chri...@gmail.com, Nov 3, 2011

Jason, could you please update the Quickstart example?

There's a comment that states:

 // In non-GWT code, use AutoBeanFactoryMagic.create(MyFactory.class);

Please update it since the class AutoBeanFactoryMagic? is deprecated in gwt 2.3. and removed in 2.4 -> We should use the Class AutoBeanFactorySource?.

Comment by ame...@gmail.com, Nov 15, 2011

Hi jasonhall. I tried, but it says

Rebinding JsonAutoBeanFactory?

Invoking generator com.google.web.bindery.autobean.gwt.rebind.AutoBeanFactoryGenerator?
ERROR? The DataJsonContainer? parameterization is not simple, but the DataJsonContainer? method does not provide a delegate ERROR? Unable to complete due to previous errors
ERROR? Deferred binding failed for 'JsonAutoBeanFactory?'; expect subsequent failures All clients connected (Limiting future permutations to: gecko1_8)

My factory looks like:

AutoBean<DataJsonObject> dataJsonObject(); AutoBean<DataJsonContainer> dataJsonContainer();

and the interface

public interface DataJsonContainer? {

List<DataJsonObject> getDataJsonObjects(); void setDataJsonObjects();
}

public interface DataJsonContainer? {

String getName(); void setName(String name);
}

Comment by jasonhall@google.com, Nov 15, 2011

Is the second interface supposed to be named DataJsonObject??

Comment by ame...@gmail.com, Nov 17, 2011

nope, it is DataJsonObject? instead of DataJsonContainer?, sorry for that

Comment by ilja.hamalainen@gmail.com, Nov 22, 2011

Hei guys! Can you update documentation about the AutoBeanFactoryMagic? class? It is deprecated now, but AutoBeanFactorySource? marked as "This is experimental, unsupported code" (ver. 2.4.0). What is the best way to create factory on the server side? Thank you!

Comment by Ognjen.F...@gmail.com, Dec 2, 2011

Hi Jason,

Is it possible to serialize JavaScriptObject? using AutoBean? Or how to create Splittable from JavaScriptObject??

Comment by fa...@hti-systems.co.za, Feb 9, 2012

Hi guys,

Why am I getting the following:

Loading inherited module 'com.google.web.bindery.autobean.AutoBean'

ERROR? Unable to find 'com/google/web/bindery/autobean/AutoBean.gwt.xml' on your classpath; could be a typo, or maybe you forgot to include a classpath entry for source?

I have added <inherits name="com.google.web.bindery.autobean.AutoBean"/> in my projects xml and added gwt-servlet-deps.jar to my class path

Help appreciated

Comment by biplav.s...@gmail.com, Mar 22, 2012

Any idea why is below exception thrown? Message says Expecting indexed data. Stack trace is pasted below. Help would be appreciated.

java.lang.AssertionError??: Expecting indexed data ERROR? at com.google.web.bindery.autobean.shared.impl.SplittableList??.<init>(SplittableList??.java:64) ERROR? at com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl??$CollectionCoder??.decode(AutoBeanCodexImpl??.java:144) ERROR? at com.google.web.bindery.autobean.shared.impl.AbstractAutoBean??.getOrReify(AbstractAutoBean??.java:241) ERROR? at


Sign in to add a comment
Powered by Google Project Hosting