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.