Put together Struts2, JPA, Hibernate and Spring

This weekend I played a bit with Struts2. Obviously my first thought was to put together “fellowship of the ring” ie Struts, Spring and Hibernate. Now, we have two ways for integrating Hibernate and I’ve chosen the Java Persistence Architecture approach, because is the latest trend in terms of persistence in the J2EE landscape.

Create your domain model

For the sake of simplicity I’ll take  a simple example that contains Books and Authors. A book has one or more authors while one author wrote one or more books. This looks like a many to many relationship and we want to be able to get, from one shoot, the book and its authors and for an author his entire list of books.

Book.java

package org.bserban.shs.model;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "book")
public class Book {
    @Id
    @GeneratedValue
    private Integer id;
    private String title;
    private String publisher;
    private String keywords;
    private String ISBN13;
    private String ISBN10;
    @ManyToMany(fetch = FetchType.EAGER)
    private List<Author> authors;
........................................

Author. java

package org.bserban.shs.model;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "author")
public class Author {
    @Id
    @GeneratedValue
    private Integer id;
    private String firstName;
    private String lastName;
    private String blog;
    @ManyToMany(mappedBy="authors",fetch = FetchType.EAGER)
    private List<Book> books;
.......................................

As you see in the code snippets above, the many to many relationship was marked with @ManyToMany annotation. We specified that the many to many relationship is mapped by Author entity too. No need to create a persistence.xml or hibernate.cfg.xml files at this moment because the whole configuration will take place in the Spring files.

Create a DAOs

First of all create a generic DAO object to keep the reference to the EntityManager and avoid duplicate code in other DAOs.

package org.bserban.shs.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public abstract class GenericJPADAO<T, ID extends Serializable> {

private Class<T> persistentClass;

protected EntityManager em;

@PersistenceContext
public void setEntityManager(EntityManager em) {
this.em = em;
}

public EntityManager getEntityManager() {
return em;
}

public void save(T entity) {
getEntityManager().persist(entity);
}

public void delete(T entity) {
getEntityManager().remove(entity);
}
public T getById(Object id) {
return getEntityManager().find(persistentClass, id);
}

By making a generic DAO class using java generics we are avoiding casting and using the Object class as parameter, in this way our methods will always have the proper type for their operation. While this is very easy with simple application it can become more complicated, but don’t forget that now we are building bricks that will help us to build our house, for more complicated logic we just simply create a facade class that will use our bricks.
BookDAO.java and AuthorDAO.java

package org.bserban.shs.dao;
import org.bserban.shs.model.Author;
public class AuthorDAO extends GenericJPADAO<Author,Integer> {
}
package org.bserban.shs.dao;
import org.bserban.shs.model.Book;
public class BookDAO extends GenericJPADAO<Book,Integer>{
}

These classes are empty so far but specific methods will probably be added.

Create your service layer

I am going to build also a generic service similar with the generic DAO class. For this example I only need basic operations that can be easily made generic. All I need is to create a generic interface called GenericService and ask for a type. Note that while GenericService is an interface for the DAOs I’ve done an abstract class because I wanted to add code to methods.

package org.bserban.shs.service;
import java.util.List;
public interface GenericService<T> {
    T create(T entity);
    void delete(T entity);
    T update(T entity);
    List<T> list(int page, int size);
}

Now, in the Services classes we need to have also a reference to the specific DAO object for that type of service. I am going to create a dao field in each class and I am going to assume that somebody will set the dao to the correct value when the service will be used.

BookService.java and AuthorService.java, their structure is identically so i will list only one here:

package org.bserban.shs.service;
import org.bserban.shs.dao.AuthorDAO;
import org.bserban.shs.model.Author;
import java.util.List;
public class AuthorService implements GenericService<Author> {
    private AuthorDAO dao;
    public Author create(Author entity) {
        dao.save(entity);
        return entity;
    }
    public void delete(Author entity) {
        dao.delete(entity);
    }
    public Author update(Author entity) {
        dao.save(entity);
        return entity;
    }
    public List<Author> list(int page, int size) {
        return dao.list(page,size);
    }
    public AuthorDAO getDao() {
        return dao;
    }
    public void setDao(AuthorDAO dao) {
        this.dao = dao;
    }
}

For the listing feature I simply added a new method in the DAOs for list, and it looks like this:

................
public List<Author> list(int page, int size) {
    Query query = this.em.createQuery("from Author order by lastName,firstName");
    query.setFirstResult((page - 1) * size);
    query.setMaxResults(size);
    return query.getResultList();
}
.................
public List<Book> list(int page, int size) {
    Query query = this.em.createQuery("from Book order by title");
    query.setFirstResult((page - 1) * size);
    query.setMaxResults(size);
    return query.getResultList();
}
..................

Create the Actions

The actions are part of the controller and they need to validate data and to provide error handling before calling the service layer. One characteristic of putting together the Spring and Struts2 is that the dependency injection is done via a constructor argument. You could do it also with setters and getters but this would expose your service class to the exterior. One could call your action via HTTP by providing a parameter with the same name of your service class which will result into an unpredictable behavior, most probably an error.

In the actions I am going to have three fields, the first is the Service reference, the second is the list of model object and the third is a solo entity used for create, update, delete.

I will only list one Action class because they are pretty similar:

public class AuthorAction extends FrontendAction {
    private GenericService<Author> service;
    private List<Author> authors;
    private Author author;
    public AuthorAction(GenericService<Author> service) {
        this.service = service;
    }
    public String list() {
        authors=service.list(page, size);
        return SUCCESS;
    }
    public String update() {
        service.update(author);
        return SUCCESS;
    }
    public String create() {
        service.create(author);
        return SUCCESS;
    }
    public String delete() {
        service.delete(author);
        return SUCCESS;
    }
......................................

I have created a FrontendAction to put the page and size parameters, since they are a common feature of both actions.  Similar, you can put here other attributes that are common for the all actions.

Now lets add our actions into struts.xml file and start to configure the Spring support. I have chosen the extension of our actions to be *.html. I also want to set the Struts2 into dev mode to debug the application if necessary. For IOC Struts2 has a property called objectFactory which let’s you to specify what is your IOC container, i set this to “spring” values. The views will be written as Freemarker templates which I consider to be a powerful template engine.

<constant name="struts.devMode" value="true"/>
<constant name="struts.action.extension" value="html"/>
<constant name="struts.objectFactory" value="spring"/>
<constant name="struts.ui.theme" value="simple"/>
<constant name="struts.ui.templateSuffix" value="ftl"/>
<constant name="struts.configuration.xml.reload" value="true"/>

Now we need to declare our actions, I’ve decided to create different name space for each action which means that the http calls will look like this: /books/…..   /authors/…..

<package name="books" namespace="/books" extends="struts-default">
    <action name="list" class="bookAction" method="list">
        <result name="success" type="freemarker">/WEB-INF/pages/books/list.ftl</result>
    </action>
</package>
<package name="authors" namespace="/authors" extends="struts-default">
    <action name="list" class="authorAction" method="list">
        <result name="success" type="freemarker">/WEB-INF/pages/authors/list.ftl</result>
    </action>
</package>

For the purpose of demonstration I am providing only the listing capability, I let you code the rest. So I need to create two templates to list the entities, they are done in the same way so i am pasting only the author’s list page:

[#ftl]
<link media="screen" type="text/css" href="${base}/resources/css/style.css" rel="stylesheet">
<div>
<table class="listing">
    <tr><td class="hed" colspan="3">List of authors</td></tr>
    <tr>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Books</th>
    </tr>
    [#list authors as author]
    <tr [#if author_index%2 = 0]class="bg"[/#if]>
        <td>${author.firstName!''}</td>
        <td>${author.lastName!''}</td>
        <td>[#if author.books??][#list author.books as book] ${book.title}[#if book_has_next],[/#if][/#list][/#if]</td>
    </tr>
    [/#list]
</table>
</div>

Glue the code with Spring

This example uses Spring 2.5.5 version. I am going to separate the configuration files in two, one is for generic configuration for JPA and transactions and the second will contain our classes glued together.

My applicationContext.xml

Declare the JPA support

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

Now declare the EntityManager bean

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean
            class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="database" value="MYSQL" />
            <property name="showSql" value="true" />
        </bean>
    </property>
</bean>

The data source used by EntityManager bean

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/example" />
    <property name="username" value="example" />
    <property name="password" value="example" />
</bean>

Now I need to configure the transaction manager for my classes and obviously I am going to use the one that supports annotations. The era for declarative transaction configuration has long gone.

<bean id="transactionManager"
    class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
<tx:annotation-driven transaction-manager="transactionManager" />

Let’s not forgot our objects, let’s tell Spring where is our application specific configuration file

<import resource="exampleContext.xml"/>
Now, all I need is to glue my classes together, basically our DAOs need the JPA beans, the Services need our DAOs and Struts Actions need our Services.
exampleContext.xml will contain the followings:
<!-- daos -->
 <bean id="authorDao" class="org.bserban.shs.dao.AuthorDAO"/>
 <bean id="bookDAO" class="org.bserban.shs.dao.BookDAO"/>
 <!-- services -->
 <bean id="authorService" class="org.bserban.shs.service.AuthorService">
     <property name="dao" ref="authorDao"/>
 </bean>
 <bean id="bookService" class="org.bserban.shs.service.BookService">
     <property name="dao" ref="bookDAO"/>
 </bean>
 <!-- action -->
 <bean id="authorAction" scope="prototype" class="org.bserban.shs.action.AuthorAction">
     <constructor-arg ref="authorService"/>
 </bean>
 <bean id="bookAction" scope="prototype" class="org.bserban.shs.action.BookAction">
     <constructor-arg ref="bookService"/>
 </bean>

Now add the transaction support to our service classes. I simply need to put the @Transactional annotation at class level which means that all method from that class support transactions.

import org.springframework.transaction.annotation.Transactional;
@Transactional
public class BookService implements GenericService<Book> {
.........................

I am going to configure also the web.xml file, where I’ll put the configuration for Struts and for Spring.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Now all we need is to hit run and see if it is working. Also we are going to need some testing data.

Database tables

Putting this line <property name=”generateDdl” value=”true” /> into EntintyManagerFactory bean configuration will cause the generation of our database tables.

tables

I just need to insert manually some sample data to be able to list them in the “list” pages.

Sample data:

INSERT INTO `author` (`id`,`firstName`,`lastName`,`blog`) VALUES  (1,'John','Doe','no blog'), (2,'Sam','Dune','no blog');
INSERT INTO `book` (`id`,`title`,`publisher`,`keywords`,`ISBN13`,`ISBN10`) VALUES  (1,'Some Random Title','The plublisher','random','0596517726','978-0596517724');
INSERT INTO `book_author` (`books_id`,`authors_id`) VALUES  (1,1);

Html Views

Let’s add a simple css file to give a decent look to our pages, all we need is to customize the table look&feel.

table.listing {
    text-align: center;
    font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
    font-weight: normal;
    font-size: 11px;
    color: #fff;
    width: 280px;
    background-color: #666;
    border: 0px;
    border-collapse: collapse;
    border-spacing: 0px;
}
table.listing td {
    background-color: #CCC;
    color: #000;
    padding: 4px;
    text-align: left;
    border: 1px #fff solid;
}
table.listing td.hed {
    background-color: #666;
    color: #fff;
    padding: 4px;
    text-align: left;
    border-bottom: 2px #fff solid;
    font-size: 12px;
    font-weight: bold;

End the result:

http://localhost:8080/books/list.html

listBooks

http://localhost:8080/authors/list.html

listAuthors

I hope I’ll have the time to continue this apps and introduce jQuery for simple actions like add/edit/delete/filter books and authors.

Cheers,

Resources

I’ll list here all the needed jars/frameworks for this sample application:

Source code sample, you can downloaded from here Struts2, Spring, JPA, Hibernate

Comments

31 Responses to “Put together Struts2, JPA, Hibernate and Spring”

  1. andrei on June 1st, 2009 7:05 am

    I found it very interesting. How come haven’t you created your view in Flex?

  2. bserban on June 1st, 2009 10:12 am

    Hi Andrei,

    I am thinking to create two frontends for this posts, one in jQuery and on Flex. I am very interested in creating an Flex app with Mate MVC for flex. It looks very promising.

    Bogdan

  3. andrei on June 2nd, 2009 8:08 am

    I am currently using Cairngorm as an MVC framework for my Flex application. What are the differences in approach between Cairngorm and Mate MVC? For what kind of applications is it more suitable to use one or another?

    Cheers,
    Andrei

  4. bserban on June 4th, 2009 3:36 am

    Hi,

    Mate looks to much easier to understand and use, and i think that for small and medium application could be a suitable solution. But first I have to write an application with made before give advices.
    This is an interesting post about Flex MVC frameworks.

    http://www.insideria.com/2009/01/frameworkquest-2008-part-6-the.html

  5. Ziv on June 8th, 2009 6:51 pm

    Just wanted to say thx, u saved me tons of time !

  6. Helmi on July 15th, 2009 2:58 am

    Hi,

    what struts2-spring-plugin version you use in this apps?
    Thanks.

  7. Configure Apache and Tomcat severs together | bogdan@j3e on August 8th, 2009 3:23 am

    […] Put together Struts2, JPA, Hibernate and Spring […]

  8. Ashish on September 2nd, 2009 1:21 am

    I tried this in tomcat 5.5, but on server startup I m getting following exception.

    Sep 2, 2009 11:46:40 AM org.apache.catalina.core.StandardContext start
    SEVERE: Error listenerStart
    java.lang.NoClassDefFoundError: org/apache/log4j/LogManager

    When I added log4j-1.2.15.jar for missing class, I am getting

    log4j:WARN No appenders could be found for logger (org.apache.commons.digester.Digester.sax).
    log4j:WARN Please initialize the log4j system properly.
    Sep 2, 2009 11:58:32 AM org.apache.catalina.core.StandardContext start
    SEVERE: Error listenerStart
    Sep 2, 2009 11:58:32 AM org.apache.catalina.core.StandardContext start
    SEVERE: Context [/LMSWebApp] startup failed due to previous errors

    this exception. Is it anything to do with log4j-1.2.15.jar?

    Please help me

  9. Calintz on September 9th, 2009 12:57 am

    Thanks for your tutorial. This combination provides us a good approach in developing web application. By the way, if my table contains more than 10 entries, how can we make it to list out subsequent records in next page?

  10. admin on September 14th, 2009 12:33 am

    Hi,

    It seems that you have a missing jar file. I am not sure which one.

    I don’t think that it is related to log4j-1.2.15.jar

  11. admin on September 14th, 2009 12:37 am

    You need to modify the html to include pagination code. The business code already includes pagination parameters:
    public List list(int page, int size) {
    return dao.list(page,size);
    }

    In the action you also have the full call to the business layer, including the pagination parameters:
    public String list() {
    authors=service.list(page, size);
    return SUCCESS;
    }

    So all you need is to pass the page and the size from the html code, like appending them to the request in this way: ……&page=2&size=10

    Hope this will work for you.

    Thanks,

  12. Joe on November 21st, 2009 5:41 pm

    Please can anyone tell the advantage of using JPA and hibernate together?

  13. bserban on November 22nd, 2009 5:24 am

    It is the same old story about using a standard vs a custom implementation. Hibernate became a “De facto” standard for the ORM persistence.

    Using JPA you could use any ORM, without any change in the code, as a persistence layer.

    There is nothing wrong to use the Hibernate’s API and not the JPA. The purpose of the article was to show hot you put those two together JPA API + Hibernate.

    Cheers,

    Bogdan

  14. Leo on December 9th, 2009 7:15 pm

    hi,

    I am new to Struts2 Hibernate and Spring. I tried this example in netbeans, but get the following errow, could you tell me what’s wrong with that? Thanks.:)

    error message is following :
    No persistence units parsed from {classpath*:META-INF/persistence.xml

  15. Leo on December 9th, 2009 8:06 pm

    hi, Bogdan

    i just fix above error, but still get following error messages, could you give me suggestions? Thanks.

    10/12/2009 12:04:50 PM com.opensymphony.xwork2.util.logging.commons.CommonsLogger error
    SEVERE: Dispatcher initialization failed
    java.lang.NullPointerException
    at org.apache.struts2.osgi.OsgiConfigurationProvider.init(OsgiConfigurationProvider.java:70)
    at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:203)
    at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55)
    at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:374)
    at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:418)
    at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
    at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
    at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:108)
    at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3800)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4450)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:526)
    at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:630)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:514)
    at org.apache.catalina.startup.HostConfig.check(HostConfig.java:1288)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:297)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
    at org.apache.catalina.manager.ManagerServlet.check(ManagerServlet.java:1473)
    at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:824)
    at org.apache.catalina.manager.ManagerServlet.doGet(ManagerServlet.java:350)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:196)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:525)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
    at java.lang.Thread.run(Thread.java:619)

  16. Mick Smith on December 17th, 2009 12:05 pm

    Thanks for your post!… you made it look so easy. I wish I can pick it up that easily!

    I have implemented something similar to yours(using this example: http://struts.apache.org/2.0.14/docs/struts-2-spring-2-jpa-ajax.html)

    Main difference is that I dont have 1 DAO object but my service layers use the entityManager to update, merge, persist, etc.

    I have an issue which I hope you can help me. I have 1 action class that will invoke 2 of those service layers and attempt to persist data. However, the action class only seems to be able to persist data on the service class it uses as its constructor. For the 2nd service class it can retrieve information ok via finders but cannot persist data into it! I get no error whatsover. I have debugged and the em.persist(obj) gets executed. what could I be missing??

    Your help is kindly appreciated

    regards
    Mick Smith

  17. eugene on January 5th, 2010 6:56 pm

    Is there any reason I’d be getting this error when implementing multiple beans as in your example:

    No unique bean of type [com.carmel.controller.service.GenericService] is defined: expected single matching bean but found 2: [actionItemsService, userService]

    I configured my application just as above – not sure why Spring thinks that the services (though implementing the same interface) are not the same.

    Thanks for your help.

  18. bserban on January 11th, 2010 10:43 am

    Hi Eugene

    Sorry for such a late answer. I need more info about your error but i guess you are using autowire or you used GenericService as type instead of AuthorService or BookService.

    Little i can say without see the code.

    Cheers.

  19. bserban on January 11th, 2010 10:44 am

    Mick,

    It looks to me more an transaction error. Check your transaction delimiters on the methods that don;t persist the values.

  20. eugene on January 11th, 2010 2:18 pm

    Hi Bogdan. Thanks for writing back. Here’s the breakdown of what I have

    GenericService.java (simple interface as above)
    UserDaoService.java (service implementing generic)
    ActionItemService.java (another service)

    extendedContext.xml (the file contains the following…)

    When I remove the settings for either the User bean or the ActionItem bean, leaving only one, everything works fine. However, when I have them both there I receive the error.

    I tried modifying my struts.properties file with various autowire modes:
    struts.objectFactory.spring.autoWire = type
    struts.objectFactory.spring.autoWire = name (def)
    struts.objectFactory.spring.autoWire = auto
    struts.objectFactory.spring.autoWire = constructor

    none worked (same error, except with “constructor” – that completely broke the application)

    Thanks for your help.

  21. eugene on January 12th, 2010 3:27 am

    after spending hours on this today, it appears that autowiring is the problem. I’m having trouble disabling it. I tried setting the rule in a struts.properties file – nothing works. is there a way to disable it?

  22. eugene on January 14th, 2010 1:43 pm

    After many hours, I figured out what I was doing wrong. In the struts.xml instead of referencing the location of the class (i.e. com.mypackage.action.MyItemAction) within the tag:

    -struts-
    -package name=”mydbitems”-
    -action name=”list” class=”com.mypackage.action.myItemAction”

    I should have been referencing the bean which was specified in the applicationContext.xml (or exampleContext.xml) file

    -struts-
    -package name=”mydbitems”-
    -action name=”list” class=”myitemAction”

    where myitemAction is defined in the exampleContext.xml as

    -bean id=”myitemAction” scope=”prototype” class=”com.mypackage.action.myItemAction”-

    Thanks for the initial response. I hope this helps someone who might be searching on a similar problem.

  23. preetu on January 20th, 2010 4:50 am

    hi ..i created complete project while running project call these two links: /authors/list.html or /books/list.html k fine then i created 2 html files inside webcontent then i got error(There is no Action mapped for namespace / and action name list. – [unknown location]
    at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:177) and i not understootd what is those two .ftl struts.xml mapped to two .ftl file inside WEB-INF obviously if create .html this will trough error .Should i create .html file were should i create and what is the use of .ftl file

  24. bserban on January 20th, 2010 11:41 am

    Hi,

    .ftl are from Freemarker templare engine. It is similar to JSP.

    You could map a default action that goes anyway you like. A default action can be added like this:

    This way the / will go to the default action.

  25. Maddy on June 22nd, 2010 9:53 pm

    I really liked your article but I had a problem when I want to insert data from JSP for one-to-many.

    To make it clear I am using model based approach so say I have a class called Preference and that has a Set which is other table.

    for normal fields I can use
    but for Set has a select with multiple=true
    How would I represent it on jsp

  26. Joseph on June 29th, 2010 12:38 am

    Hi Sir,

    I downloaded the Source files and I created a new project using existing files then add the required libraries but when i’m trying to run it. It was an error saying “The module has not been deployed.”

    Any comments or suggestion?

    Thanks in advance…

  27. bserban on July 8th, 2010 6:21 am

    @Joseph

    When do you receive this error? Is it when you start Tomcat or it is related to your IDE?

    Bogdan

  28. Alexp on October 7th, 2010 11:10 am

    Hi,

    Thanks for the lesson

    I try to use the getById method of the GenericJPADAO class but it doesn’t work (nullpointerexception)

    persistantClass attribute is null and there is no setter in your code to instantiate it

    java.lang.NullPointerException
    org.hibernate.impl.SessionImpl.get(SessionImpl.java:836)
    org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:182)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    java.lang.reflect.Method.invoke(Method.java:597)
    org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:198)
    $Proxy13.find(Unknown Source)
    org.bserban.shs.dao.GenericJPADAO.getById(GenericJPADAO.java:32)
    org.bserban.shs.service.UtilisateurService.getById(UtilisateurService.java:45)
    org.bserban.shs.service.UtilisateurService.getById(UtilisateurService.java:1)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    java.lang.reflect.Method.invoke(Method.java:597)
    org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
    org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    $Proxy16.getById(Unknown Source)
    org.bserban.shs.action.UtilisateurAction.prepare(UtilisateurAction.java:28)
    com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:134)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
    com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:94)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:165)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:179)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:176)
    com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
    org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:488)
    org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)

  29. paul on November 15th, 2010 12:20 am

    cool! i also wanna share this very spoon fed version of Spring + Hibernate + JPA combo

    http://www.adobocode.com/spring/spring-with-hibernate-annotations

    tnx

  30. Ramkumar D on April 28th, 2011 4:51 am

    Hi Im getting below exception can anyone help me?

    14:40:32,328 INFO [TomcatDeployer] deploy, ctxPath=/strutsSpringJPA, warUrl=file:/C:/jboss-4.0.1sp1/server/default/deploy/strutsSpringJPA.war/
    14:40:33,593 INFO [Engine] StandardContext[/strutsSpringJPA]Initializing Spring root WebApplicationContext
    14:40:33,593 INFO [ContextLoader] Root WebApplicationContext: initialization started
    14:40:33,593 INFO [XmlWebApplicationContext] Refreshing org.springframework.web.context.support.XmlWebApplicationContext@139ef3a: display name [Root WebApplicationContext]; startup date [Thu Apr 28 14:40:33 GMT+05:30 2011]; root of context hierarchy
    14:40:33,593 INFO [XmlBeanDefinitionReader] Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
    14:40:33,625 INFO [XmlBeanDefinitionReader] Loading XML bean definitions from ServletContext resource [/WEB-INF/exampleContext.xml]
    14:40:33,656 INFO [XmlWebApplicationContext] Bean factory for application context [org.springframework.web.context.support.XmlWebApplicationContext@139ef3a]: org.springframework.beans.factory.support.DefaultListableBeanFactory@e776f7
    14:40:33,750 INFO [DefaultListableBeanFactory] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@e776f7: defining beans [org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor#0,authorDao,bookDAO,authorService,bookService,authorAction,bookAction,entityManagerFactory,dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy
    14:40:33,765 INFO [DriverManagerDataSource] Loaded JDBC driver: com.mysql.jdbc.Driver
    14:40:33,781 INFO [LocalContainerEntityManagerFactoryBean] Building JPA container EntityManagerFactory for persistence unit ‘SHS_Example’
    14:40:33,781 INFO [DefaultListableBeanFactory] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@e776f7: defining beans [org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor#0,authorDao,bookDAO,authorService,bookService,authorAction,bookAction,entityManagerFactory,dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.config.internalTransactionAdvisor]; root of factory hierarchy
    14:40:33,781 ERROR [ContextLoader] Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘authorDao’ defined in ServletContext resource [/WEB-INF/exampleContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.transaction.config.internalTransactionAdvisor': Cannot create inner bean ‘(inner bean)’ of type [org.springframework.transaction.interceptor.TransactionInterceptor] while setting bean property ‘transactionInterceptor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)': Cannot resolve reference to bean ‘transactionManager’ while setting bean property ‘transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘transactionManager’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Cannot resolve reference to bean ‘entityManagerFactory’ while setting bean property ‘entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:485)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:170)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:413)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:735)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:369)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:251)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:190)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3827)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4343)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.apache.commons.modeler.BaseModelMBean.invoke(BaseModelMBean.java:503)
    at org.jboss.mx.server.RawDynamicInvoker.invoke(RawDynamicInvoker.java:150)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:642)
    at org.apache.catalina.core.StandardContext.init(StandardContext.java:5441)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.apache.commons.modeler.BaseModelMBean.invoke(BaseModelMBean.java:503)
    at org.jboss.mx.server.RawDynamicInvoker.invoke(RawDynamicInvoker.java:150)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:642)
    at org.jboss.web.tomcat.tc5.TomcatDeployer.performDeployInternal(TomcatDeployer.java:289)
    at org.jboss.web.tomcat.tc5.TomcatDeployer.performDeploy(TomcatDeployer.java:92)
    at org.jboss.web.AbstractWebDeployer.start(AbstractWebDeployer.java:374)
    at org.jboss.web.WebModule.startModule(WebModule.java:62)
    at org.jboss.web.WebModule.startService(WebModule.java:40)
    at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:272)
    at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:222)
    at sun.reflect.GeneratedMethodAccessor42.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:144)
    at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
    at org.jboss.mx.server.Invocation.invoke(Invocation.java:72)
    at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:249)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:642)
    at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:891)
    at $Proxy0.start(Unknown Source)
    at org.jboss.system.ServiceController.start(ServiceController.java:416)
    at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:144)
    at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
    at org.jboss.mx.server.Invocation.invoke(Invocation.java:72)
    at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:249)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:642)
    at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:177)
    at $Proxy28.start(Unknown Source)
    at org.jboss.web.AbstractWebContainer.start(AbstractWebContainer.java:360)
    at org.jboss.deployment.MainDeployer.start(MainDeployer.java:964)
    at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:775)
    at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:738)
    at sun.reflect.GeneratedMethodAccessor49.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:144)
    at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
    at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:122)
    at org.jboss.mx.server.Invocation.invoke(Invocation.java:74)
    at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:131)
    at org.jboss.mx.server.Invocation.invoke(Invocation.java:74)
    at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:249)
    at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:642)
    at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:177)
    at $Proxy8.deploy(Unknown Source)
    at org.jboss.deployment.scanner.URLDeploymentScanner.deploy(URLDeploymentScanner.java:305)
    at org.jboss.deployment.scanner.URLDeploymentScanner.scan(URLDeploymentScanner.java:463)
    at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.doScan(AbstractDeploymentScanner.java:204)
    at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.loop(AbstractDeploymentScanner.java:215)
    at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.run(AbstractDeploymentScanner.java:194)
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.transaction.config.internalTransactionAdvisor': Cannot create inner bean ‘(inner bean)’ of type [org.springframework.transaction.interceptor.TransactionInterceptor] while setting bean property ‘transactionInterceptor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)': Cannot resolve reference to bean ‘transactionManager’ while setting bean property ‘transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘transactionManager’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Cannot resolve reference to bean ‘entityManagerFactory’ while setting bean property ‘entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:229)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:122)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1274)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1042)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:485)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:170)
    at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:87)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:98)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:84)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:66)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:296)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:334)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1368)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
    … 83 more

  31. charan on November 12th, 2011 10:52 pm

    i configure same project but i am getting the above error please help on this.i configured persistence.xml in META-INF