The following blogpost will be a little different than my others. It will not focus on ECM related development but rather GWT development.
Although not really related to ECM, I figured I'd write a tutorial on how to set up a GWT application with a Spring/Hibernate backend since it took me a long time to get it working exactly the way I wanted. There are a lot of tutorials but I thought they all missed something.
All source code of this tutorial is available. I added a zipped version of the complete GWT project as attachment to this blogpost.
The tutorial is based on the following 2 tutorials (I learned it from those, then adapted it abit):
The goals of this tutorial is to create a simple GWT application with a Spring powered backend that uses Hibernate to persist data into a database.
We will create an application that can do CRUD operations using a basic interface.
To stay in the ECM world, we’ll name the application ECMSoftware and our data objects will represent ECM products (name, vendor name, price, components).
Video of the final application:
- Java (ofcourse!)
- Basic GWT experience
- Basic Spring experience
- Basic Hibernate experience (we’ll use Hibernate with annotations in this tutorial)
- Eclipse with GWT plugin (we’re using GWT SDK 2.3.0)
- Spring 3.0.5 jars (+dependencies)
- Hibernate 3.6.6 jars (+dependencies)
- Spring4Gwt 0.0.1 jar (only version available)
- browser with GWT Developer plugin (Mozilla Firefox / Google Chrome)
- A database server (this tutorial will use SQL Server 2008, but you’re free to use whatever you want
3. Required Jars Overview
The following jars should all be present under war/WEB-INF/lib
- gwt-servlet.jar (added by GWT)
- hibernate3.jar (add to build path)
- hibernate-jpa-2.0-api-1.0.1.Final.jar (add to build path)
- log4j-1.2.16.jar (add to build path)
- org.springframework.beans-3.0.5.RELEASE.jar (add to build path)
- org.springframework.context-3.0.5.RELEASE.jar (add to build path)
- org.springframework.core-3.0.5.RELEASE.jar (add to build path)
- org.springframework.orm-3.0.5.RELEASE.jar (add to build path)
- org.springframework.transaction-3.0.5.RELEASE.jar (add to build path)
In Eclipse, create a new project of type Web Application Project and name it ECMSoftware, also provide a package for your application, ie. com.docbyte.gwt.tutorial.ecmsoftware. Uncheck the Use Google Apps Engine option and click Finish. Leave the Generate GWT Sample Code option enabled so we can inspect the generated code.
The GWT project template has automatically generated some files and folders for you:
src: will contain all the source code for the application
- server: serverside only code (will be compiled to Java)
- Note: See client-note.
- test: package to create your Java (unit) tests
war: represents the entire web application
- WEB-INF: standard WEB-INF folder with web.xml and a lib directory
ECMSoftware.html: standard html template
- ECMSoftware.css: some basic css
Start with deleting the client.GreetingService, client.GreetingServiceAsync, server.GreetingServiceImpl and shared.FieldVerifier classes. Then remove all the code from client.ECMSoftware so you have only this left:
Proceed by removing unused code from the html page:
- remove the entire <table> under <body>
- change <title> under <head> to ECM Software Application
- change <h1> under <body> to ECM Software Application
- leave the rest of the html page untouched.
We’ll start by writing the following code:
and then running our application (rightclicking on the project and selecting Run As > Web Application). Eclipse will compile all the resources and show you a link with the development url:http://127.0.0.1:8888/ECMSoftware.html?gwt.codesvr=127.0.0.1:9997. You can then open the url and you should see a popup saying “It seems to be working” and a page with a big title.
Note: This url is just a development url, your final url will not contain all these parameters.
Note: The page will most likely load (very) slowly, this is only while running the application from Eclipse. Your final application will load normally.
Knowing that the basic setup of our GWT project is working, we can proceed to create our data model and clientside interfaces.
We’ll start by making our data entity, which is a standard Java POJO. It is mandatory that the POJO implements java.io.Serializable or com.google.gwt.user.client.rpc.IsSerializable and has a no-argument constructor!
I’ll create this under the shared.model package. I put it under shared because both the client as the server will use it.
In GWT you have to define a service interface in the client package, accompanied by an asynchronous counterpart of the service. The implementation will reside in the server package but we’ll create this later on in the tutorial. So, start by creating a ECMProductService under the client.service package. This service must extend com.google.gwt.user.client.rpc.RemoteService and has to be annotated with com.google.gwt.user.client.rpc.RemoteServiceRelativePath. This annotation indicates where the service (aka the servlet implementation) can be found.
You can see Eclipse marks the interface as erronic although it is syntactically correct. This is because the GWT plugin cannot find the async counterpart (because we haven’t created it yet).
Create (or generate) the ECMProductServiceAsync (the name must be the name of the service + Async). Inspect the method-signature carefully, you’ll see the following things:
- the names of the methods are the same
- they can be marked public, but that is optional and has no impact on the code
- they have void as return type
- their arguments are the same as in the original service, but they have an extra argument: an AsyncCallback with as generic type the return type of the original method
That is all of the clientside stuff (except for building the html page in the EntryPoint, which we will do later on) so we can start with the server side implementation.
Start by creating DefaultECMProductService under server.service and make sure to implement client.ECMProductService.
Note: In standard GWT, you would have to extend GWT’s RemoteServiceServlet and create a servlet-entry for your class in web.xml. Here Gwt4Spring will handle the http-request in their servlet and then invoke our service implementation.
So you don’t have to extend anything, just implement the service. Then add the following to web.xml so Gwt4Spring can handle the requests.
You can choose the name of the servlet as you wish.
Note: Note the ‘ecm’ part in ‘/ecmsoftware/ecm/*’. It is mandatory that the second part of the url-pattern is the same as the first part in our annotation of our clientside service (@RemoteServiceRelativePath(“ecm/productService”)). You can change this, but you have to change it in both places. Also, you cannot change it to ‘gwt’ because this will interfere with default GWT behaviour and will cause your css-file to be ignored (GWT creates a css under ../gwt/xxx.css) – I know this from experience.
This service implementation will be Spring powered so you can use all your Spring novelties on it. You can do everything in the application context, or use annotations. In our example we’ll use annotations.
To work with Spring and Hibernate (or any library for that matter), make sure all the jars are placed under war/WEB-INF/lib (see chapter 3) and the required jars are added to the Eclipse build path.
In our service implementation we will not call the database directly, but rather use a DAO that will do the data-access for us. Also, we’ll mark our methods as @Transactional. The readOnly property should always be true unless you are creating/updating/deleting atleast 1 object from the database.
Note: You can also mark the entire class as @Transactional(readOnly=true). This will make all the methods readOnly=true by default. Then you only have to annotate the create/update/delete methods with @Transactional(readOnly=false) to override the class-based default.
So the flow of our application is as follows:
- User does something in UI.
- Spring4Gwt receives this call and calls the Spring service with that name.
- The Spring service calls the DAO (injected through Spring @Autowired annotation).
- The DAO uses the HibernateTemplate (injected through Spring @Autowired annotation ) to call Hibernate and do database actions.
- The result is returned to the UI.
Our Service implementation and DAO look like this:
If we annotate our POJO model class (=ECMProduct) with the correct annotation so Hibernate can correctly map it to the database, our Spring-powered Java backend is finished. We can do a first test by simply running the application again. If it starts up without errors (see the log in the Console tab in Eclipse, we have included all the necessary jars and can proceed by creating a user interface. If you have errors they will most likely be NoClassDefFoundErrors or ClassNotFoundExceptions. They can mostly be solved by including all the correct jars.
In our example we will create a user interface using Java code in the our EntryPoint class (=ECMSoftware). GWT also allows the creation of UI’s using XML with GWT’s UiBinder. This is out of scope for this tutorial.
The interface we want to create is a panel with 3 tabs:
- one tab to create a new product
- one tab to update an existing product after getting it from the database
- one tab to give an overview of all the existing products and a way to remove them
We will start by providing a root panel in our html page in which we will add our UI components. Just add a <div> element below your <h1>-title and call it root.
That is all we need to do in the html page, the rest is code based. The code to construct the page with the tabs is too long to put in the tutorial so I left it out to improve the. Also, I assume most people who read this already have a (basic) understanding of GWT so creating the interface won’t be a problem. All source code is available in the zip file.
5. Running and Compiling
By now you should be almost crazy by always running the application in Development Mode which makes you wait and wait and wait and wait while loading the page.
When GWT has finished compiling the code, deploying the webapplication is easy-as-cake. The war folder is basicly the webapp root so it can be deployed on any application server that is a servlet container (Tomcat, Jboss, ...). I mostly use Tomcat so all I have to do is put the war folder under webapps, rename it to whatever I want start the Tomcat server.
- I have not included any of the required jars in the zipped source code to make sure I’m not violating any license agreement. It shouldn’t be any problem finding the required jars as I have listed the required jars in chapter 3.
A very big issue in with GWT and Hibernate is that GWT only supports a small subset of Java classes to be emulated. Hibernate often returns PersistentList, PersistentBag, ... instead of the regular ArrayList. These Hibernate classes are not supported by GWT and cannot be returned to the client.
In this tutorial I have provided a GWTUtil class that will change those Persistent collections to a supported ArrayList. This is ofcourse not a longterm solution.
You can use frameworks like Gilead to avoid this, or use SennMagic’s GWTPersistentEntityManager to change the collections at runtime (or write it yourself).
- As I said before, nothing binds you to use Spring and Hibernate with annotations. This example is perfectly possible with application-context.xml Spring config and Hibernate’s infamous Xxx.hbm.xml files.
- One of the trickiest things in GWT - imho – is the a button in a table that does something with an entity on that row (as we created here with the removebutton). I created a custom ClickHandler that takes some arguments to be able to know which entity we’re working with. The other tricky part is to then instantly remove the row from the table (without refreshing the entire table). If you have a better way to do this, please let me know.
- This tutorial won’t work when you want to use GWT’s RequestFactory approach. If you want to try and work out a solution, feel free to ask my help. I’m curious to see how easily we can adapt the Spring4Gwt code to make it work for RequestFactory.
- If you want to use a different database, remove the jtds jar, put your own driver-jar in the lib folder and update the database.properties file with the correct driver, url, user, password and dialect.
I do not claim any of this tutorial code to be optimal or best practice, or even guaranteed to work on any system, or in any browser.
I hope this tutorial was helpful, feel free to post all your questions/remarks/feedback.
Source code is added as attachment
Please contact us to help you with your digital journey
Enter your email address below to have a digest of our featured blog posts sent to you