Grails

Webflow tries to serialize domain-class objects within a service

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Won't Fix
  • Affects Version/s: 1.0.3
  • Fix Version/s: 1.0.5
  • Component/s: WebFlow
  • Labels:
    None
  • Environment:
    Linux (Ubuntu 8.04)

Description

I am using services to implement business logic in my web-flow. Because I do not want to make my domain-classes serializable, these services communicate back to the flow using POGO's.

The problem appears to be that Grails is tying to serialize the domain-class objects used within the services (i.e. - implements Serializable thrown).

I have created a cut-down version of the app (attached) that replicates the problem. Adding a book to the shopping cart will result in the exception.

Activity

Hide
Stefan Armbruster added a comment -

It seems that the Hibernate session (and therefore all objects residing in its cache) are put into the flow scope.

Show
Stefan Armbruster added a comment - It seems that the Hibernate session (and therefore all objects residing in its cache) are put into the flow scope.
Hide
Jesse Jackson added a comment -

This really should be attended to ASAP, it basically renders the webflow feature useless.

Show
Jesse Jackson added a comment - This really should be attended to ASAP, it basically renders the webflow feature useless.
Hide
Graeme Rocher added a comment -

Webflow stores objects in serialized state, it is required by the implementation. The Hibernate session is stored in order to support lazy loading of associations. However, I don't see how this makes web flow useless. What is the problem with making your classes implement serializable?

Show
Graeme Rocher added a comment - Webflow stores objects in serialized state, it is required by the implementation. The Hibernate session is stored in order to support lazy loading of associations. However, I don't see how this makes web flow useless. What is the problem with making your classes implement serializable?
Hide
Randall Dietz added a comment -

As a fan of keeping the domain separate from presentation, I'm not comfortable with having to impose the serializable constraints on all my domain objects just so I can reference them within a webflow.

I'm happy that objects that I wish to store in the webflow must be serializable. The issue here is that if I simply want to reference an instance of a domain object (e.g. - make a decision in the webflow based on a domain object value), that object must be serializable.

Is that truly the case?

Show
Randall Dietz added a comment - As a fan of keeping the domain separate from presentation, I'm not comfortable with having to impose the serializable constraints on all my domain objects just so I can reference them within a webflow. I'm happy that objects that I wish to store in the webflow must be serializable. The issue here is that if I simply want to reference an instance of a domain object (e.g. - make a decision in the webflow based on a domain object value), that object must be serializable. Is that truly the case?
Hide
Ian Roberts added a comment -

I know this issue was closed wontfix a while ago, but for the benefit of anyone else who falls foul of this - if you want to read info from a domain object in an action but don't need it later in the flow (so don't want to make it serializable), the trick I use is to .discard() the object, which removes it from the hibernate cache. As discard() doesn't actually invalidate the object (it just tells hibernate to forget about it) you can even do this immediately after getting it:

on("someEvent") {
  def myObj = DomainClass.findByWidget(flow.widget)
  myObj.discard()
  // some logic using myObj
}.to "nextState"

If you need to update the object in the DB you can save it with flush:true and then discard it to remove it from the cache:

on("someEvent") {
  def myObj = DomainClass.findByWidget(flow.widget)
  myObj.foo = flow.updatedValue
  myObj.save(flush:true)
  myObj.discard()
}.to "nextState"
Show
Ian Roberts added a comment - I know this issue was closed wontfix a while ago, but for the benefit of anyone else who falls foul of this - if you want to read info from a domain object in an action but don't need it later in the flow (so don't want to make it serializable), the trick I use is to .discard() the object, which removes it from the hibernate cache. As discard() doesn't actually invalidate the object (it just tells hibernate to forget about it) you can even do this immediately after getting it:
on("someEvent") {
  def myObj = DomainClass.findByWidget(flow.widget)
  myObj.discard()
  // some logic using myObj
}.to "nextState"
If you need to update the object in the DB you can save it with flush:true and then discard it to remove it from the cache:
on("someEvent") {
  def myObj = DomainClass.findByWidget(flow.widget)
  myObj.foo = flow.updatedValue
  myObj.save(flush:true)
  myObj.discard()
}.to "nextState"
Hide
Randall Dietz added a comment -

@Ian - Cheers mate! I appreciate your taking the time to share the solution. I'll have a look at webflows again.

Show
Randall Dietz added a comment - @Ian - Cheers mate! I appreciate your taking the time to share the solution. I'll have a look at webflows again.
Hide
John Thompson added a comment -

@Ian - thanks for posting on this. Very helpful. I've spent hours googling on this issue.

I found adding this to the controller works too:

class FooController {

    def transient myService

    def transient sessionFactory

    def someFlow{
       on("someEvent") {
       
       myService.someMethod()
       . . .        
       sessionFactory.currentSession.clear()
    }.to "nextState"
Show
John Thompson added a comment - @Ian - thanks for posting on this. Very helpful. I've spent hours googling on this issue. I found adding this to the controller works too:
class FooController {

    def transient myService

    def transient sessionFactory

    def someFlow{
       on("someEvent") {
       
       myService.someMethod()
       . . .        
       sessionFactory.currentSession.clear()
    }.to "nextState"
Hide
Ignacio Cases added a comment -

@John - thank you very much for posting your solution, the only one working for me after several hours of investigating the issue.

Show
Ignacio Cases added a comment - @John - thank you very much for posting your solution, the only one working for me after several hours of investigating the issue.

People

Vote (7)
Watch (8)

Dates

  • Created:
    Updated:
    Resolved: