Announcement Announcement Module
Collapse
No announcement yet.
JPA Data Repository Serialization (using them in Spring Webflow context) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JPA Data Repository Serialization (using them in Spring Webflow context)

    Hello everyone,

    I'm trying to use a Spring Data JPA repository inside a webflow, and unfortunately i'm stuck with this error:

    Could not serialize flow execution; make sure all objects stored in flow or flash scope are serializable
    org.springframework.webflow.execution.repository.s napshot.SerializedFlowExecutionSnapshot.<init>(Ser ializedFlowExecutionSnapshot.java:75)"
    First of all, let me explain my motivation: i'm using webflow faces integration in my web application. I'm using a DataTable primefaces ui component that uses a LazyDataModel backing bean (where i want to have my JPA Repository) to obtain the page records on demand.

    Here is a snippet of my JPA Repository and also my LazyDataModel:

    Code:
    @Repository
    public interface XptoRepository extends JpaRepository<Xpto, Long> { }
    Code:
    public class XptoLazyDataModel extends LazyDataModel<Xpto> {
    
    	private XptoRepository repository;
    (...)
    }
    To experience this behavior you can easily use the booking-faces sample application, change HotelLazyDataModel to use a Spring Data Jpa Repository instead of a Service that uses an explicit EntityManager.

    Does anyone has any idea how to use a Spring Data JPA Repository inside a webflow?

    Using:
    Spring Webflow: 2.3.1
    Spring Data: 1.0.2


    Thanks in advance

    Best Regards

  • #2
    I'm not 100% sure I follow your post, but as far as I can tell you are storing a XptoLazyDataModel on some SWF scope (flash or flow).
    This is on itself no issue, but remember that everything stored on flow or flash scope (and any other scope besides request for that matter) needs to be serializable.

    The datamodel probably is serializable, but the reference it has to a "XptoRepository", is by itself probably not serializable.
    The fact that it is not serializable is not the issue (you don't want repositories to be serializable) the issue is the reference by itself.
    If you are following the Spring centric approach, the normal way of working would be creating a POJO application controller wich contains a reference to your repository instead (actually the prefered way would be something coarser grained like a facade or service).
    The application controller can then be called from your flow and retrieve the information from the repository.
    The retrieved data can then be stored inside a datamodel which is eventually returned by the application controller to the flow and stored by the flow on flash or flow scope.

    Comment


    • #3
      Thanks for your response.

      I'm well aware that all objects inside viewScope and flowScope should be serializable. However i'm not achieving proper datatable pagination without executing on the fly the proper query to obtain my page. And in regarding to DataModel of JSF, the objective of that object is to be used as a facade to your data (not to be build on every request of a paginated table, for example). Offcourse i can load all objects into DataModel object, but with huge datasets this will cause memory problems.

      Let me give you a proper example from booking faces sample app. In Booking-Faces (that comes with SpringWebflow distribution) sample app you have the following flow service support class HotelLazyDataModel:

      Code:
      public class HotelLazyDataModel extends LazyDataModel<Hotel> {
      
          private static final long serialVersionUID = -8832831134966938627L;
      
          SearchCriteria searchCriteria;
      
          BookingService bookingService;
      
          private Hotel selected;
      
          public HotelLazyDataModel(SearchCriteria searchCriteria, BookingService bookingService) {
      	this.searchCriteria = searchCriteria;
      	this.bookingService = bookingService;
          }
      
          @Override
          public List<Hotel> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, String> filters) {
      	searchCriteria.setCurrentPage(first / pageSize + 1);
      	return bookingService.findHotels(searchCriteria, first, sortField, sortOrder.equals(SortOrder.ASCENDING));
          }
      (...)
      }
      You can see that the pagination is properly handled by BookingService. If you then go to BookingService impl:

      Code:
      @Service("bookingService")
      @Repository
      public class JpaBookingService implements BookingService, Serializable {
      
          private static final long serialVersionUID = 1L;
      
          private EntityManager em;
      
          @PersistenceContext
          public void setEntityManager(EntityManager em) {
      	this.em = em;
          }
      (...)
      }
      You can see that they use directly the EntityManager! Since i'm using SpringData i want obviously to reuse the JpaRepositories in my service. I'm not that happy to have to rewrite queries to obtain the objects again directly using EntityManager!

      Maybe i'm doing this wrong, but i still cannot figure out the best way to integrate Spring Data with SpringWebflow and JSF Model objects.

      Best Regards

      Comment


      • #4
        Ok, I saw the sample. For starters the sample does indeed store the JpaBookingService together with the datamodel.
        I understand why they do it, but seen from the SWF point of view it is a bit weird to store your services on view scope (or any scope for that matter) since repositories, services, facades and all the likes are stateless, they don't need to be stored.

        The JpaRepository from Spring data is just a template helper class for, well, JPA repositories.
        Your problem here is that JpaRepository does not extend Serializable (which is also correct - from Spring data's point of view).
        So as far as I can tell your 'XptoRepository' is not Serializable, which is causing SWF to complain.

        You could try to make you repository implementation also implement Serializable.
        However, in that case you are probably extending from SimpleJpaRepository which uses the EntityManager provided by constructor injection.
        Since the superclass does not implement Serializable, the EM will be null after deserialization by SWF.

        I think your best shot would be to make the data model @Configurable and make the reference to the @Autowired repository transient.
        This way the repository is not serialized (like it should be) but is again wired when a new instance of the datamodel is created (for example after deserialization)

        Comment


        • #5
          Thanks for you help.

          I will try do that. If i succeed i'll post the solution here.

          Thanks once again.

          Best Regards

          Comment


          • #6
            Yep, it's so simple, but for some reason it elude me from the start. Use the @Configurable annotation and add a transient field with @Autowired!

            Thank you so much.

            Big help!

            Best regards

            Comment


            • #7
              Hi
              Can you put the changes done by you to integrate the booking example with @Configurable? I tried to follow the steps but it was not working.

              Comment

              Working...
              X