0

I'm struggling with editing and updating nested objects because of this Hibernate Lazy Loading error that I keep hitting again and again.

In my application:

  1. I bind an Image Set to a product.
  2. I've used the formatter to convert the imageset for use in a select box, so the user can select the image set.
  3. It works well if the form succeeds, the object binds and the relationship saves correctly.
  4. But if there's a validation failure, whenever the UI layer tries to access the nested object value I get the dreaded Lazy Initialization/No Session error!

So I tried to write a method to initialize the related objects as a workaround:

@Transactional
public void initObject(Variant variant) {
    Hibernate.initialize(variant.getOption1());
    Hibernate.initialize(variant.getOption2());
    Hibernate.initialize(variant.getOption3());
    Hibernate.initialize(variant.getImageSet());
}

The first 3 lines in that method work (these are unidirectional one to one), but the fourth doesn't (this is a many to one), it still says no proxy.

I've also tried making everything Eager fetch type.

Neither of these worked.

The issue is probably that I'm creating the parent object, it doesn't get saved to the database when there's a validation fault, but the nested object is for whatever reason a lazy proxy object regardless of the fetch type (see formatter below).

How can I fix this?

This is the formatter component:

@Component
public class ImageSetFormatter implements Formatter<ProductImageSet> {

    private static Logger logger = LogManager.getLogger(VariantController.class.getName());

    @Autowired
    private ProductImageService imageService;

    @Override
    public ProductImageSet parse(String s, Locale locale) throws ParseException {
        logger.entry();

        Long imageSetId = Long.valueOf(s);
        logger.exit();
        return imageService.getImageSet(imageSetId);
    }

    @Override
    public String print(ProductImageSet productImageSet, Locale locale) {
        logger.entry();

        logger.exit();
        return Long.toString(productImageSet.getId());
    }
}

Stacktrace when the line Hibernate.initialize(variant.getImageSet()) is called:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.LazyInitializationException: could not initialize proxy - no Session org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863) javax.servlet.http.HttpServlet.service(HttpServlet.java:644) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837) javax.servlet.http.HttpServlet.service(HttpServlet.java:725) org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330) org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)

Relevant Object Relationships:

   @Entity
@Table(name="variants")
@EntityListeners({AuditingEntityListener.class})
public class Variant extends AbstractAuditable<Customer, Long> {

    @OneToOne
    private VariantOptionValue option1;

    @OneToOne
    private VariantOptionValue option2;

    @OneToOne
    private VariantOptionValue option3;

    ...

     @ManyToOne
    @JoinColumn(name="image_set_id")
    @LazyCollection(LazyCollectionOption.FALSE )
    private ProductImageSet imageSet;



}


@Entity
@Table(name="product_image_set")
@EntityListeners({AuditingEntityListener.class})
public class ProductImageSet extends AbstractAuditable<Customer, Long> {


    public ProductImageSet(String label)
    {
        this.label = label;
    }

    public ProductImageSet(){

    }

    @Basic
    @Column(length = 50, nullable = false)
    private String label;

    @OneToMany(mappedBy = "imageSet", fetch = FetchType.EAGER)
    private List<ProductImage> images;

    @OneToMany(mappedBy = "imageSet", fetch = FetchType.EAGER)
    private List<Variant> variants;

    private int sequence;

    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;

    ...
}
3
  • Can you post the actual stacktrace of the exception that you are getting? The error message may give a clue as to what the error is. Can you also post your objects that you are using, or give a detailed description of their relationships (one X has many Y, one Y has one Z etc) Commented Sep 16, 2014 at 2:56
  • Can you post a description of object relationships as well? You talk about a parent object, but I need to know what is the parent and what is the child Commented Sep 16, 2014 at 3:03
  • Note that I tried a few variations already of fetch = FetchType.EAGER, the LazyCollection was just my latest attempt at a fix. Commented Sep 16, 2014 at 6:16

1 Answer 1

0

Two things you might want to try.

1- add the OpenEntityManagerInViewFilter

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
</filter>

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

2- Add your entity/form/model to the session

@Controller
@SessionAttributes("yourEntityFormModel")
public class YourController {
    ...
}

--------- Update

What happen is that, in a method annotated that runs inside a transaction, Hibernate will be able to retrieve the relationships from that entity on demand.

So, the example below works fine.

@Transactional
public void updateEmployeesFromDepartment(int depId) {

    Department dep = departmentRepository.findOne(dep.getId());
    for (Employee e : dep.getEmployees()) {
        // update whatever you want
    }

}

But I don't expect this to work...

public void updateEmployeesFromDepartment(int depId) {

    Department dep = departmentRepository.findOne(dep.getId());
    for (Employee e : dep.getEmployees()) {
        // update whatever you want
    }

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

9 Comments

See this for why number 1 is a bad idea.
Also, if this is a RESTful application, number 2 totally destroys any RESTful implementation as you are making making it stateful by adding the model to the session.
@JamesMassey I understand the point... arguable tho... This is one of those partners that once saved the day but people (!?!) don't like it anymore. I do prefer to load all required information to view beforehand but if I can help the friend here, he can decide later if he likes it or not. :)
That's why I didn't downvote your answer. I agree that this was once a solution, but it might not be helpful in this case. I was just pointing out the possible flaws in case the OP didn't understand the implications
How did you find out it's a RESTful implementation? I couldn't find anything that specified that.
|

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.