3 Replies Latest reply on Feb 20, 2014 6:48 PM by Pieter Grobler

    Adding item to OneToMany collection in @SessionScoped CDI bean

    Pieter Grobler Newbie

      Hi all,

       

      I am trying to add an item into a collection of an entity that is held inside a @SessionScoped bean. Using an Arquillian test case, I now want to access this entity. My code is as follows:

       

      Thing.java

      @Entity
      public class Thing implements Serializable
      {
      
        private static final long serialVersionUID = 1L;
      
      
        @Id
        @GeneratedValue
        private Long id;
      
        @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "thing")
        private Set<Widget> widgets;
      
      
        public Long getId()
        {
        return id;
        }
      
      
        public void setId(Long id)
        {
        this.id = id;
        }
      
      
        public Set<Widget> getWidgets()
        {
        return widgets;
        }
      
      
        public void setWidgets(Set<Widget> widgets)
        {
        this.widgets = widgets;
        }
      
      }
      

       

      Widget.java:

      @Entity
      public class Widget implements Serializable
      {
      
        private static final long serialVersionUID = 1L;
      
      
        @Id
        @GeneratedValue
        private Long id;
      
        @ManyToOne(cascade = CascadeType.PERSIST)
        @JoinColumn(name = "thingId")
        private Thing thing;
      
      
        public Long getId()
        {
        return id;
        }
      
      
        public void setId(Long id)
        {
        this.id = id;
        }
      
      
        public Thing getThing()
        {
        return thing;
        }
      
      
        public void setThing(Thing thing)
        {
        this.thing = thing;
        }
      
      
      }
      

       

      ThingService.java:

      @SessionScoped
      public class ThingService implements Serializable
      {
      
        private static final long serialVersionUID = 1L;
      
      
        @Inject
        private ThingDataAccess thingDA;
      
        @Inject
        private EntityManager em;
      
        private Thing thing;
      
        public Thing saveThing()
        {
        thing = new Thing();
        return thingDA.save(thing);
        }
      
        public Widget saveWidget()
        {
        Widget widget = new Widget();
        widget.setThing(thing);
        em.refresh(widget);
        return thingDA.save(widget);
        }
      
        public Thing getThing()
        {
        return thing;
        }
      
      
      }
      

       

      ThingDataAccess.java:

      @Stateless
      public class ThingDataAccess
      {
      
        @Inject
        private EntityManager em;
      
        public Thing save(Thing thing)
        {
        if(thing.getId() != null)
        em.merge(thing);
        else
        em.persist(thing);
        return thing;
        }
      
        public Widget save(Widget widget)
        {
        if(widget.getId() != null)
        em.merge(widget);
        else
        em.persist(widget);
        return widget;
        }
      
      }
      

       

      ThingServiceTest.java:

      @RunWith(Arquillian.class)
      public class ThingServiceTest
      {
        @Deployment
        public static Archive<?> createTestArchive()
        {
        return ShrinkWrap
        .create(WebArchive.class, "test.war")
        .addClasses(Thing.class, Widget.class, ThingDataAccess.class,
        ThingService.class, Resources.class)
        .addAsResource("META-INF/test-persistence.xml",
        "META-INF/persistence.xml")
        .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
        .addAsWebInfResource("test-ds.xml", "test-ds.xml");
        }
      
        @Inject
        private ThingService service;
      
        @Resource
        private UserTransaction userTransaction;
      
        private static Thing thing;
      
        @Before
        public void init() throws Exception
        {
        userTransaction.begin();
        thing = service.saveThing();
        }
      
        @Test
        @InSequence(1)
        public void testThing() throws Exception
        {
        assertNotNull(thing);
        userTransaction.commit();
        }
      
        @Test
        @InSequence(2)
        public void testWidget() throws Exception
        {
        Widget widget = service.saveWidget();
        assertNotNull(widget);
        thing = service.getThing();
        assertNotNull(thing.getWidgets());
        userTransaction.commit();
        }
      
      }
      

       

       

      My questions to any helpful Arquillian evangelist out there would be:

       

      1. Is everything set up correctly?
      2. Why do I get java.lang.IllegalArgumentException: Entity not managed for my em.refresh(widget) statement?
      3. When I replace em.refresh(widget) with em.merge(widget), I get no errors, but the test fails with thing.getWidgets() returning null. Why is the thing's widget collection not also updated with the latest db state?
      4. Eventually, what I would like to test in testWidget() is assertTrue(thing.getWidgets().size() == 1). Is there a better way to do all this? For instance, can I get away without using UserTransaction? After all, we are calling with Servlet 3.0 protocol, and that should be session-friendly, right?

       

      Many thanks in advance for any tips.