0 Replies Latest reply on Jun 25, 2011 6:27 AM by wujek

    How far to go with CDI in design - custom Iterable example

    wujek

      Hi. I have the following use case: we have a class that has potentially hundreds / thousands of child object in the collection. We load them lazily, in pages. The objects are never needed all at once, they are only accessed serially during a report generation or similar. To that end, the parent class is a custom implementation of Iterable, whose Iterators have the logic to fetch pages and manage the paging state of the children collection. The call looks like:
      for (XXX x : parent) {
          // process child elements, paging happens in iterator
      }
      The iterators need an instance of a custom stateless service Service, that in turn uses DAOs and some other stuff to load pages. The iterator itself has the state which says which page it is, which item in the page will be returned, and it knows when to fetch new pages. (There is some complex stuff going on there to deal with new / deleted elements from the collection while iteration takes place, but it is irrelevant here.)


      I see two basic options of implementing this with CDI:
      1. the 'normal' route - the custom Iterable (which is managed by CDI) has the Service as its dependency, and the iterator() method creates a new instance of the PagingIterator with the Service as argument, and returns it. The Service dependency of Iterable is injected by CDI automatically.
      2. the CDI route - the custom Iterable (again, CDI managed) has an instance of PagingIteratorProvider injected, and iterator() method simply calls get() on it. The Provider is a bean that takes the Service as a dependency in its constructor, and it is injected by CDI. We can't use Instance / Provider generated by CDI automatically, as we have the Service dependency. Then, the PagingIterator performs its actions.


      Option 1 seems very simple, but it seems to violate a few principles as well: it uses new, and it takes a dependency which it never directly uses, only to pass it to some objects that it instantiates (with new). Seems kind of dirty, but is simple.


      Option 2 decouples the custom Iterable from the Service completely, instead requiring a custom Provider, which adds for the whole class being more testable - I can provide a mock and can unit test the Iterable implementation to death (it works with its own iterators sometimes, and I should test exception handling and other normal / abnormal conditions). This testability is impaired in route 1. Similarly, I can test the PagingIterator as it takes the Service as dependency, but this is the case in option 1 as well.


      On the other hand, the CDI route is much much more complex and hard to understand for people that don't get on well with DI and testability (like my tech lead, who still lives in EJB 2.1 era). The graph of objects can get quite deep. I implemented it using the second approach, but stumbled upon criticism from my superiors, that it is to complex. (Which is funny, as the really complex part is the streaming / paging support and its state management and fault tolerance and the like, and this on the other hand was acclaimed and deemed 'good'.)


      How would you, experienced CDI users, go about this use case? Do you try to use CDI always, and 'no new' is the goal, or do you have some guidelines?


      Regards.