0 Replies Latest reply on Jun 29, 2014 2:39 AM by pavelpscheidl

    Lazy initialization of ArrayList attribute fails (Glassfish to WildFly migration)

    pavelpscheidl

      I migrated a JEE war website from GlassFish 4 to JEE. I am using Java Server Faces with CDI Named beans. One of my beans directly calls a dao class method to retrieve Category object. The Category class has some attributes, one of them is List<Merchandise> merchandise. This is by default lazily initialized (Merchandise is another table). The Category object is retrieved, but when trying to work with List<Merchandise> merchandise, which is lazily initialized, the persistence bag is empty and following error is thrown:


      javax.servlet.ServletException: failed to lazily initialize a collection of role: cz.pscheidl.velkoobchod.domain.Category.merchandise, could not initialize proxy - no Session

       

      I think I know what kind of problem this is. The @Named bean called EshopBean does not provide any transaction when calling this object. This should not work in Glassfish, but somehow it did. After setting EAGER initialization of List<Merchandise> merchandise in Category object, everything works. So does JOIN FETCH in related named query.

       

       

      EshopBean object looks like this:

      @Named

      @ViewScoped

      public class EshopBean implements Serializable {

       

       

          @Inject private CategoryDao categoryDao;

          @Inject private MerchandiseDao merchandiseDao;

          @Inject private ActiveSession activeSession;

          @Inject private OrderDao orderDao;

          @Inject private Logger logger;

       

       

          private List<Category> categoryList;

          private List<OrderItem> offeredMerchandise;

       

       

          @PostConstruct

          @TransactionAttribute(TransactionAttributeType.REQUIRED)

          public void updateOfferedMerchandise() {

              List<Category> allCateogries = categoryDao.findByOffered(true);

              offeredMerchandise = new ArrayList<>();

              categoryList = new ArrayList<>();

            

              allCateogries.parallelStream().filter(e -> {

              return !e.getMerchandise().isEmpty();

              }).forEach(e -> {

              categoryList.add(e);

            

              e.getMerchandise().parallelStream().filter(m -> {

                  return m.isOffered();}).forEach(m -> {

                  offeredMerchandise.add(createOrderItem(m));

                  });

            

              });

          }

      }

       

      Category object looks like this (methods omitted):


      @Entity

      @NamedQueries(

              {

                  @NamedQuery(name = "findCategoryByName", query = "SELECT c FROM Category c WHERE c.name = :name"),

                  @NamedQuery(name = "findAllCategories", query = "SELECT c FROM Category c"),

                  @NamedQuery(name = "categoryHasMerchandise", query = "SELECT COUNT(m) FROM Merchandise m WHERE m.category = :categoryId"),

                  @NamedQuery(name = "findCategoryByOffered", query = "SELECT c FROM Category c WHERE c.offered = :offered")

              }

      )

      public class Category implements Serializable {

       

       

          @Id

          @GeneratedValue(strategy = GenerationType.IDENTITY)

          private long id;

          @Column(unique = true)

          @Size(min = 1, max = 255)

          private String name;

          @Column(nullable = false)

          private boolean offered;

          @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)

          @JoinColumn(name = "CATEGORY_ID")

          public List<Merchandise> merchandise;

      }

       

       

      CategoryDaoImpl (some methods omitted):

      Stateless

      public class CategoryDaoImpl implements CategoryDao {

          @PersistenceContext

          private EntityManager entityManager;

       

          @Override

          @TransactionAttribute(TransactionAttributeType.REQUIRED)

          public List<Category> findByOffered(boolean activity) {

              Query findByOfferedQuery = entityManager.createNamedQuery("findCategoryByOffered", Category.class);

              findByOfferedQuery.setParameter("offered", true);

              return findByOfferedQuery.getResultList();

          }

      }

       

      The method calling chain is like this: EshopBean.updateOfferedMerchandise()  - > CategoryDaoImpl.findByOffered() - > return to EshopBean.updateOfferedMerchandise(). I'd guess that both are annotated as transactional, findByOffered method is annotated as Required. Yet Hibernate in WildFly says there is no session (i think it expects the same transactional context).

       

      What am I doing wrong ?