Hey,

Ideally I wanted to be able to construct a workflow without having to deal with
external resources, and pass everything I need into the constructor.

I.E.

        public class SomeAnnotator extends JCasAnnotator_ImplBase {
          private Type someType;
          private Foo foo;
          private Bar bar;

          SomeAnnotator(Type someType, Foo foo, Bar bar) {
                // set everything
          }
         
          public void process(JCas jcas) {
                // loop over annotations of "someType" and perform something 
with foo & bar
          }
        }

Since UIMA requires a default constructor, I've been getting away with using a
wrapper that deals with all the initialization logic and then forwards all calls
to a delegate.
This is not ideal, but it allows me to test annotator logic in isolation of
initialization logic.  
Note: this uses uimaFIT.

        public class SomeAnnotatorWrapper extends
org.uimafit.component.JCasAnnotator_ImplBase {
          public static final String SOME_TYPE_NAME = "someType";
          public static final String FOO_KEY = "foo";
          public static final String BAR_KEY = "bar";

          @ConfigurationParameter(name = SOME_TYPE_NAME, mandatory = true)
          private String someTypeName;  

          @ExternalResource(key = FOO_KEY, api = ExternalResourceLocator.class,
mandatory = true)
          private Foo foo;

          @ExternalResource(key = BAR_KEY, api = ExternalResourceLocator.class,
mandatory = true) 
          private Bar bar;
          
          private SomeAnnotator delegate;
          
          private initDelegate(TypeSystem ts) {
                Type someType = ts.getType(someTypeName);
                delegate = new SomeAnnotator(someType, foo, bar);
          }

          public void process(JCas jcas) {
                if (delegate == null) initDelegate(jcas.getTypeSystem());
                delegate.process(jcas);
          }
        }

The problem is that this still requires 2 separate implementations of
ExternalResourceLocators for Foo and Bar, and they can't share dependencies
without some type of global state.

        public class FooResource implements ExternalResourceLocator {
          public Foo getResource() {
            Baz baz = ???; // Have to make a new baz here
            return new Foo(baz, ...);
          }
          
          // rest of Resource methods not shown
        }

        public class BarResource implements ExternalResourceLocator {
          public Bar getResource() {
            Baz baz = ???; // Here as well since can't share
            return new Bar(baz, ...);
          }
          
          // rest of Resource methods not shown
        }


What I would like is for SomeAnnotatorWrapper to remain the same (although maybe
with an extra @Inject with each @ExternalResource) and then have some dependency
injection framework
deal with how to construct Foo & Bar.

That last line was kind of vague, because I don't know myself.  This is what I
was wondering about.
I suppose one solution would have the respective Injector for Guice/Spring
passed in as another @ExternalResource and then a subclass could take that and
inject the other field(s).

However, this may be too uimaFIT specific, which was why I was hoping for a
solution in UIMA core.




Reply via email to