The project was build with Maven and is available via GIT https://github.com/poseidonjm/basic-crud
If you don't have Egit you can install Help -> Install New Software...
I am using Eclipse Java EE IDE for Web Developers.
You should install Maven http://maven.apache.org/download.html download apache-maven-3.0.4-bin.zip
Install maven plugin Help -> Install New Software...
m2e-wtp - http://download.jboss.org/jbosstools/updates/m2eclipse-wtp
I am using postgreSQL 8.4
Here I am include modules like RequestFactory, GXT, UIBinder, GIN and set my locale to es_PE (spanish-Perú).
So where is the code? Simple I am using Gin and is like Guice for GWT projects. It means you can use the powerful Dependency Intection in your GWT code.
What is Dependency Intection?
In a nutshell "Never use new use @Inject instead". Guice will create your object and initialized injected fields.
In GIN I need a Ginjector and create this with GWT.create().
private final ClientGinjector injector = GWT.create(ClientGinjector.class);
Here I get a ColaboradorPanel to attach to the RootPanel. A Ginjector need a Module.
The next code was extracted from http://cleancodematters.com/2011/05/19/gwt-requestfactory_with_gin/
Here I configure how GIN will create objects. My Messages Interface should be a Singleton, my ClientBundle AppImages too. In RequestFactory is needed an EventBus here I am using a SimpleEventBus and is a Singleton. There is a Provider method createRequestFactory that create my AppRequestFactory Interface and initialized it with a SimpleEventBus. More about GIN http://code.google.com/p/google-gin/.
In GWT there is not Java Reflection and GXT need access to the properties. For that purpose here is the interface ColaboradorProxyProperties.
I created a SaveEvent to be fired when a user click on Save Button.
Inside there is already created a SaveHandler.
I created this class using a GWTP Plugin for Eclipse http://code.google.com/p/gwt-platform/wiki/EclipsePlugin Once installed you can use this wizard to easily create your events.
I entered the EventName: SaveEvent and check the Has Handlers box.
The Editor is the Dialog where the user entered your information and click on Save button. Here the SaveEvent is fired and the method save of SaveHandler is executed. Here I call the flush method to update the object modified in the editor. An next if the driver has not eny errors I hide the Editor and fire the context RequestContext.
What Is a RequestContext
In RequestFactory all changes in an object are done inside a context. When you want to persist your changes call the fire methot of a context. Your changes are sent to the server and are saved to a database. It means you can make many changes before sent your changes to the server.
Next I Inject Messages interface using Field Injection.
@Inject Messages messages;
Then I use Constructor Injection to initialized required variables.
public ColaboradorPanel(final Binder uiBinder, EventBus eventBus, Provider<AppRequestFactory> provider, Driver driver, ColaboradorEditor editor)
What happens first Constructor Injection or Field Injection?
The answer is Constructor Injection. It means you can't use messages variable inside the constructor because you will get a NullPointerException. If you need a variable inside a constructor inject it using Constructor Injection.
For create a GXT Grid you need create a proxy, loader and a store. Inside the proxy I use two helper function createRequestSortInfo createRequestFilterConfig to get sort info and filter info. This is needed because in Request Factory you cannot sent any object to the server. You only can sent interfaces that extends ValueProxy or EntityProxy. You sent a EntityProxy if there is an Entity Implementation on the server It means if you have a table in a database. For other objects use ValueProxy.
For create objects and edit In RequestFactory with GWT Editor. I use one method persist()
Create an Object with GWT Editor
First I declare a field member
private ColaboradorProxy colaborador;
If I wanna create an object I create en empty Object
colaborador = cs.create(ColaboradorProxy.class);
Then bind the object with the Editor
Next show the Editor
When the user see the Editor or Dialog will see empty TextFields because is binded with an empty object.
Then the user fill the Form and click on Save. The SaveEvent is fired and The SaveHandler is executed. Here I still have an empty object I you do a System.out.println(colaborador.getAge()) you will get nothing then I call the method flush() on driver and the empty object is update with the editor information the user was entered next you can do System.out.println(colaborador.getAge()) an will get what you want.
Next I fire the context and sent my changes to server.
Edit an Object with GWT Editor
Get the object selected
colaborador = grid.getSelectionModel().getSelectedItem();
And repeat the above steps.
When the user see the editor will see the information selected and can do changes and save them because It is binded with an selected object and is not empty. Here the same happens if you don't call the method flush() on driver your object won't be updated.
Two way for creating UiBinder
When you use UiBinder you should have two files ColaboradorPanel.java and ColaboradorPanel.ui.xml
Your java file may be writed in two ways:
If you want to extend from Window you can see http://www.sencha.com/forum/showthread.php?181348-(beta2)-Editor-extends-Window-doesn-t-work
All fields that need binding should be declared like class fields. If the widget is only in UiBinder and not declared like class field the binding with GWT Editor does not work.
In UiBinder all widgets are create by GWT. If you need pass an argument by UiBinder you can use
In another way you can pass the argument in java code and your field should be annotated with @UiField(provided=true) what means the object will be created by java code and not by UiBinder.
For add events I use @UiHandler("save") annotation where "save" identifies the button Save.
I am using a ClientBundle for application images and this class is injected by GIN where is needed and is not necessary use GWT.create.
There is not database table associated with this class. RequestFactory need a two fields in every domain class "id" and "version" these are columns in database table too.
Here I have my entity class. In eclipse I can use a wizard to generate this entity class.
First you should enable JPA Facet in your eclipse project.
You need configure a data source Window -->Show View --> Data Source Explorer
and create a new connection
Right click on your package and select New --> JPA Entities from tables
RequestFactory with Guice
RequestFactory is not integrate with Guice por default. In that case there is a helpful set of classes that make RequestFactory injectable https://github.com/etiennep/injected-requestfactory. I only did copy and paste of that classes.
Here I configure GuiceFilter. And GuiceServletContextListener.
In Guice you can configure all servlets and filters in java code here I configure my InjectedRequestFactoryServlet not use web.xml anymore. More info http://code.google.com/p/google-guice/wiki/ServletModule.
Here I configured my connections parameters.
Here I use injection fields to inject the Entity Manager and an Util class Paginate. Entity manager is initialized by Guice http://code.google.com/p/google-guice/wiki/JPA .
In JPA all objects are not persisted before commit the transaction. In Guice there is a useful annotation @Transactional http://code.google.com/p/google-guice/wiki/Transactions that made the method transactional.
This class that extend PagingLoadResultBean is needed for objects that will be shown in a GXT Grid.
This class use CriteriaBuilder for paginate a database table. http://www.ibm.com/developerworks/java/library/j-typesafejpa/
In Request Factory you work with interfaces that are Proxy and require a locator. This is a generic locator for all Proxies.
This is the object that you use in your GWT code and is initialized using GWT.create sent to the server and Request Factory does the magic to translate this proxy in an entity object. This proxy extend EntityProxy because represent a domain class or a database table.
For each database table I create a Service or RequestContext. The proxy ColaboradorPagingLoadResultProxy is required for GXT.
Here I configure all my services.
Internationalization with GWT
I use two properties files
Go to project path and write the command mvn gwt:i18n
Is generated in target/generated-sources
You should add to build path right click on generated-sources/gwt folder Build Path --> Use as Source Folder.
You can use command mvn gwt:run to launch the Hosted Mode.