Don't fully understand @Factory
imcmahon Jun 26, 2008 12:31 AM
Marks a method as a factory method for a context variable. A factory method is called whenever no value is bound to the named context variable, and is expected to initialize the value of the context variable. There are two kinds of factory methods. Factory methods with void return type are responsible for outjecting a value to the context variable. Factory methods which return a value do not need to explicitly ouject the value, since Seam will bind the returned value to the specified scope. This annotation supports use of the Seam 'factory component' pattern.
The messages example uses the void return type version, as such:
@DataModel private List<Message> messageList; @DataModelSelection @Out(required=false) private Message message; @PersistenceContext(type=EXTENDED) private EntityManager em; @Factory("messageList") public void findMessages() { messageList = em.createQuery("from Message msg order by msg.datetime desc") .getResultList(); }
Presumably, whenever #{messageList} is encountered in the view, Seam will invoke findMessages() if necessary and then outject the value of messageList in the context so the EL expression can render it.
In my example, I tried it both ways. Done as above, my code looks like this:
@DataModel private List<String> things; @Factory("things") public void findThings() { things = new ArrayList<String>(); things.add("One thing"); things.add("Two thing"); things.add("Red thing"); things.add("Blue thing"); }
That's in a SFSB. I traced through all the code, and when #{things} is evaluated, it figures out that the factory method needs to be run, the factory method runs which populates the things member of my SFSB, but then it either outjects the return value of the factory method, which is null, or just runs the factory method and gives up! I'm not 100% sure what's going on there, but it doesn't seem correct either way.
On the other hand, if I let the Factory method return the List value, as such:
@Factory("things") public List<String> findThings() { List<String> things = new ArrayList<String>(); things.add("One thing"); things.add("Two thing"); things.add("Red thing"); things.add("Blue thing"); return things; }
then it works correctly and my view is populated! All the examples do it the other way, which is why I'm concerned, and I'm not sure if the benefits that @DataModel gives you are available if I do it this way...