1

Despite using configuration below I got lazy initialize error:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: beans.Restaurant.tags, no session or session was closed

and here the

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>RestFinderWebApp</display-name>
<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.htm</url-pattern>
</servlet-mapping>
<welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <!-- <welcome-file>index.html</welcome-file> -->
</welcome-file-list>
<!-- Spring security: -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/applicationContext-security.xml,
        /WEB-INF/spring-servlet.xml
    </param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

spring-servlet.xml:

    <?xml  version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <context:annotation-config />
    <tx:annotation-driven transaction-manager="txManager" />
    <bean id="txManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory" />
        </property>
    </bean>
    <bean id="jspViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean class="org.springframework.jmx.export.MBeanExporter">
        <property name="autodetect" value="false" />
        <property name="assembler">
            <bean id="jmxAssembler"
                class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
                <property name="attributeSource">
                    <bean
                        class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
                </property>
            </bean>
        </property>

    </bean>

    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource"
        p:basename="messages" />

    <bean id="openSessionInViewInterceptor"
        class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
    <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="myPersistence" />
        <property name="dataSource" ref="dataSource" />
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="false" />
                <property name="generateDdl" value="true" /> 
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
            </bean>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        (...)
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                (...)
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.connection.useUnicode">true</prop>
                <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
            </props>
        </property>
    </bean>
    <tx:annotation-driven />
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <bean id="myUserDAO" class="dao.UserDAO">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <bean id="myRestaurantDAO" class="dao.RestaurantDAO">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <bean name="/mojekonto.htm" class="web.HomeUserController">
        <property name="userDAO" ref="myUserDAO" />
        <property name="restaurantDAO" ref="myRestaurantDAO" />
        <property name="loggedUser" ref="LoggedUser" />
    </bean>

</beans>

my controller:

public class HomeUserController extends MultiActionController {
private UserDAO userDAO;
private TagDAO tagDAO;

public void setTagDAO(TagDAO tagDAO) {
    this.tagDAO = tagDAO;
}

public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
}

private LoggedUser loggedUser;

public void setLoggedUser(LoggedUser loggedUser) {
    this.loggedUser = loggedUser;
}

private RestaurantDAO restaurantDAO;


public void setRestaurantDAO(RestaurantDAO restaurantDAO) {
    this.restaurantDAO = restaurantDAO;
}

private FollowDAO followDAO;

public void setFollowDAO(FollowDAO followDAO) {
    this.followDAO = followDAO;
}
private CommentDAO commentDAO;


public void setCommentDAO(CommentDAO commentDAO) {
    this.commentDAO = commentDAO;
}
@InitBinder
protected void initBinder(HttpServletRequest request,
        ServletRequestDataBinder binder) throws Exception {

    super.initBinder(request, binder);

    binder.registerCustomEditor(List.class, "tags",new CustomCollectionEditor(List.class){

        @Override
        protected Object convertElement(Object element) {
            Tag tag = new Tag();

            if (element != null) {
                int id = Integer.valueOf(element.toString());
                tag.setId(id);
            }
            return tag;
        }
    });

}
public ModelAndView mojekonto(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

    User user = loggedUser.getLoggedUser();
    ModelMap modelMap = new ModelMap();
    Restaurant restaurant = new Restaurant();
    Restaurant userRestaurant = new Restaurant();
    userRestaurant = restaurantDAO.findRestaurantByUser(user.getUsername());

    modelMap.addAttribute("user", user);
    modelMap.addAttribute("restaurant", restaurant);
    modelMap.addAttribute("userRestaurant", userRestaurant);

    return new ModelAndView("mojekonto", modelMap);
}

My class - restaurant:

    @Entity
@Table(name="restaurants")
public class Restaurant {
    @Id
    @GeneratedValue
    private int id;
    private String name;
    private String street;
    private String city;
    private String country;
    private String postal_code;
    private String telephone;
    private String logo;
    private String image;
    private String description;
    private float longitude;
    private float latitude;
    private Date last_update;
    @ManyToMany //it works fine...
    @JoinTable(name="user_restaurant_owner",
            joinColumns={@JoinColumn(name="restaurant_id")},
            inverseJoinColumns={@JoinColumn(name="username")})
    private List<User> owner;
    @ManyToMany //but that doesn't...
    @JoinTable(name="restaurant_tag",
            joinColumns={@JoinColumn(name="restaurant_id")},
            inverseJoinColumns={@JoinColumn(name="tag_id")})
    private List<Tag> tags;
        //getters and setters:

my view jsp:

 <c:forEach items="${userRestaurant.tags}" var="current">
do something
</c:forEach>

I got error when it is in "{userRestaurant.tags}"

3 Answers 3

3

Your config looks correct with the SpringOpenEntityManagerInViewFilter so you SHOULDN'T have to resort to eager fetching or having to pre-traverse the collection in your controller. I have a very similar configuration and pattern in an app I'm working on, and it's working without problems. One thing you could try is to add a blank context location to your DispatcherServlet configuration. Haven't checked, but I think it has some default behaviour to load context according to global config otherwise. This will cause the dispatcher servlet to, in effect, load a separate context rather than just creating a blank one, inheriting from the one created by the ContextLoaderListener (which is what you want it to do).

So, to your <servlet> declaration of the DispatcherServlet, add:

<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value></param-value>
</init-param>

Update: Using the hibernate transaction manager looks a bit odd as well (considering you are using a JPA entity manager). Try changing that to use the Jpa Transaction manager instead.

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

Update 2: Looking over your config again, it looks like you are using a weird mix of JPA and Hibernate. For instance, you are definig two transaction managers. Why? Also, you are using the org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter (which is JPA/EntityManager), while at the same time using the org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor (which is Hibernate/Session). How are you looking up your entities in your DAO? Using the hibernate session or the JPA EntityManager? It might be better to stick with either JPA or Hibernate to minimize collisions.

I've also had trouble getting the Open*InViewInteceptor's to work. The filters seem more stable (you have org.springframework.orm.hibernate3.support.OpenSessionInViewFilter, for instance if you decide on hibernate pure).

Sign up to request clarification or add additional context in comments.

Comments

2

You only have access to the Hibernate Session in the DAO layer. If your associations don't have a FetchType configured, or if they have FetchType.LAZY, then you have two choices, both inside the DAO:

  1. Use Hibernate.initialize
  2. Get some aspect of the association which forces Hibernate to initialize it

Example 1: Hibernate.initialize(myEntity.getMyAssociation());

Example 2:

if(myEntity.getMyAssociation() != null) {
   myEntity.getMyAssociation().size(); // forces the association to be loaded
}

I generally use example 2, because then I can also take advantage of BatchSize for Hibernate to optimize lazy fetches.

-----------EDIT 1-----------

Example for this case using HibernateTemplate and a callback:

   public Restaurant load(final Long id) {
    // need to drop down to Hibernate because of lazy loading, and make sure all properties are loaded
    HibernateCallback<Restaurant> callBack = new HibernateCallback<Restaurant>() {
        public User doInHibernate(Session session) throws HibernateException {
            Query query = session.createQuery("from Restaurant r where r.id=:id").setInt("id", id);
            Restaurant restaurant = (Restaurant)query.uniqueResult();
            Hibernate.initialize(restaurant.getOwner());
            Hibernate.initialize(restaurant.getTags());             
            return restaurant;
        }
    };
    return getHibernateTemplate().execute(callBack);

}

-----------EDIT 2----------- And here's how to do it directly in Hibernate:

@Repository
public class RestaurantDAOImpl implements RestaurantDAO {
    private SessionFactory factory;

    @Autowired
    public RestaurantDAOImpl(SessionFactory factory) {
        this.factory = factory;
    }   

    public Restaurant load(Long id) {
       Query query = session.createQuery("from Restaurant r where r.id=:id").setInt("id", id);
       Restaurant restaurant = (Restaurant)query.uniqueResult();
       Hibernate.initialize(restaurant.getOwner());
       Hibernate.initialize(restaurant.getTags());
       /* --OR --
       if(restaurant.getTags() != null) {
          restaurant.getTags().size();
       }
       */           
       return restaurant;
    }
}

2 Comments

How to do that in my class restaurantDAO? : public class RestaurantDAO { private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory){ this.hibernateTemplate = new HibernateTemplate(sessionFactory); } public void saveRestaurant(Restaurant restaurant){ hibernateTemplate.save(restaurant); } public List<Restaurant> GetAllRestaurants(){ return hibernateTemplate.loadAll(Restaurant.class); } }
If you are using HibernateTemplate, then you need to drop down into Hibernate via a callback. Current Spring standards are not to do that, but to call Hibernate directly. I can show you either one. Which would you prefer?
0

try FetchType.EAGER or fetch tags manually before referencing them.

@ManyToOne(fetch = FetchType.EAGER)
@JoinTable(name="restaurant_tag",
joinColumns={@JoinColumn(name="restaurant_id")},
inverseJoinColumns={@JoinColumn(name="tag_id")})
private List<Tag> tags;

2 Comments

Unless you always want the association to be populated, configuring an EAGER fetch is not necessarily a good idea. In fact, the Hibernate tools by default set all associations to be LAZY.
I agree, EAGER fetch is dangerous. I suggest you to set the FetchType.EAGER and see if the Exception is fixed, and then restore the default LAZY fetchtype and fetch the tag list manually when you load your Restaurant from the db (I did not see that in the code you posted).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.