You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by re...@apache.org on 2013/06/01 22:38:58 UTC

svn commit: r1488594 - in /uima/sandbox/uimafit/trunk/uimafit/src: main/java/org/apache/uima/fit/component/ main/java/org/apache/uima/fit/component/initialize/ main/java/org/apache/uima/fit/factory/ main/java/org/apache/uima/fit/internal/ test/java/org...

Author: rec
Date: Sat Jun  1 20:38:58 2013
New Revision: 1488594

URL: http://svn.apache.org/r1488594
Log:
[UIMA-2801] Allow multi-valued external resources
- Added support for multi-valued external resources
- Added test cases

Added:
    uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/internal/ResourceList.java   (with props)
Modified:
    uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/Resource_ImplBase.java
    uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/initialize/ExternalResourceInitializer.java
    uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ConfigurationParameterFactory.java
    uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java
    uima/sandbox/uimafit/trunk/uimafit/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java

Modified: uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/Resource_ImplBase.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/Resource_ImplBase.java?rev=1488594&r1=1488593&r2=1488594&view=diff
==============================================================================
--- uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/Resource_ImplBase.java (original)
+++ uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/Resource_ImplBase.java Sat Jun  1 20:38:58 2013
@@ -67,7 +67,7 @@ public abstract class Resource_ImplBase 
     return resourceName;
   }
 
-  public void afterResourcesInitialized() {
+  public void afterResourcesInitialized() throws ResourceInitializationException {
     // Per default nothing is done here.
   }
 }

Modified: uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/initialize/ExternalResourceInitializer.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/initialize/ExternalResourceInitializer.java?rev=1488594&r1=1488593&r2=1488594&view=diff
==============================================================================
--- uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/initialize/ExternalResourceInitializer.java (original)
+++ uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/component/initialize/ExternalResourceInitializer.java Sat Jun  1 20:38:58 2013
@@ -33,10 +33,12 @@ import org.apache.uima.fit.component.Ext
 import org.apache.uima.fit.descriptor.ExternalResource;
 import org.apache.uima.fit.descriptor.ExternalResourceLocator;
 import org.apache.uima.fit.internal.ReflectionUtil;
+import org.apache.uima.fit.internal.ResourceList;
 import org.apache.uima.resource.ResourceAccessException;
 import org.apache.uima.resource.ResourceInitializationException;
 import org.apache.uima.resource.ResourceManager;
 import org.apache.uima.resource.impl.ResourceManager_impl;
+import org.springframework.beans.SimpleTypeConverter;
 
 /**
  * Configurator class for {@link ExternalResource} annotations.
@@ -115,12 +117,7 @@ public final class ExternalResourceIniti
       }
 
       // Obtain the resource
-      Object value;
-      try {
-        value = context.getResourceObject(key);
-      } catch (ResourceAccessException e) {
-        throw new ResourceInitializationException(e);
-      }
+      Object value = getResourceObject(context, key);
       if (value instanceof ExternalResourceLocator) {
         value = ((ExternalResourceLocator) value).getResource();
       }
@@ -135,15 +132,49 @@ public final class ExternalResourceIniti
       // instance.
       if (value != null) {
         field.setAccessible(true);
+        
         try {
-          field.set(object, value);
-        } catch (IllegalAccessException e) {
-          throw new ResourceInitializationException(e);
+          if (value instanceof ResourceList) {
+            // Value is a multi-valued resource
+            ResourceList resList = (ResourceList) value;
+            
+            // We cannot do this in ResourceList because the resource doesn't have access to
+            // the UIMA context we use here. Resources are initialize with their own contexts
+            // by the UIMA framework!
+            List<Object> elements = new ArrayList<Object>();
+            for (int i = 0; i < resList.getSize(); i++) {
+              Object elementValue = getResourceObject(context, resList.getResourceName()
+                      + PREFIX_SEPARATOR + ResourceList.ELEMENT_KEY + "[" + i + "]");
+              elements.add(elementValue);
+            }
+
+            SimpleTypeConverter converter = new SimpleTypeConverter();
+            value = converter.convertIfNecessary(elements, field.getType());
+          }
+          
+          try {
+            field.set(object, value);
+          } catch (IllegalAccessException e) {
+            throw new ResourceInitializationException(e);
+          }
+        }
+        finally {          
+          field.setAccessible(false);
         }
-        field.setAccessible(false);
       }
     }
   }
+  
+  private static Object getResourceObject(UimaContext aContext, String aKey)
+          throws ResourceInitializationException {
+    Object value;
+    try {
+      value = aContext.getResourceObject(aKey);
+    } catch (ResourceAccessException e) {
+      throw new ResourceInitializationException(e);
+    }
+    return value;
+  }
 
   /**
    * Scan the context and initialize external resources injected into other external resources.

Modified: uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ConfigurationParameterFactory.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ConfigurationParameterFactory.java?rev=1488594&r1=1488593&r2=1488594&view=diff
==============================================================================
--- uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ConfigurationParameterFactory.java (original)
+++ uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ConfigurationParameterFactory.java Sat Jun  1 20:38:58 2013
@@ -29,11 +29,11 @@ import java.util.Map;
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.IllegalClassException;
 import org.apache.uima.UIMA_IllegalArgumentException;
+import org.apache.uima.fit.factory.ExternalResourceFactory.ResourceValueType;
 import org.apache.uima.fit.internal.ReflectionUtil;
 import org.apache.uima.fit.internal.propertyeditors.PropertyEditorUtil;
 import org.apache.uima.resource.ConfigurableDataResourceSpecifier;
 import org.apache.uima.resource.CustomResourceSpecifier;
-import org.apache.uima.resource.ExternalResourceDescription;
 import org.apache.uima.resource.Parameter;
 import org.apache.uima.resource.ResourceCreationSpecifier;
 import org.apache.uima.resource.ResourceSpecifier;
@@ -337,7 +337,8 @@ public final class ConfigurationParamete
       String name = (String) configurationData[i * 2];
       Object value = configurationData[i * 2 + 1];
 
-      if (value == null || value instanceof ExternalResourceDescription) {
+      if (value == null
+              || ExternalResourceFactory.getExternalResourceParameterType(value) != ResourceValueType.NO_RESOURCE) {
         continue;
       }
 

Modified: uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java?rev=1488594&r1=1488593&r2=1488594&view=diff
==============================================================================
--- uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java (original)
+++ uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/factory/ExternalResourceFactory.java Sat Jun  1 20:38:58 2013
@@ -19,6 +19,7 @@
 
 package org.apache.uima.fit.factory;
 
+import static java.util.Arrays.asList;
 import static org.apache.uima.UIMAFramework.getResourceSpecifierFactory;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.canParameterBeSet;
 import static org.apache.uima.fit.factory.ConfigurationParameterFactory.createConfigurationData;
@@ -43,6 +44,7 @@ import org.apache.uima.fit.descriptor.Ex
 import org.apache.uima.fit.factory.ConfigurationParameterFactory.ConfigurationData;
 import org.apache.uima.fit.internal.ExtendedExternalResourceDescription_impl;
 import org.apache.uima.fit.internal.ReflectionUtil;
+import org.apache.uima.fit.internal.ResourceList;
 import org.apache.uima.resource.CustomResourceSpecifier;
 import org.apache.uima.resource.DataResource;
 import org.apache.uima.resource.ExternalResourceDependency;
@@ -142,7 +144,7 @@ public final class ExternalResourceFacto
     List<Parameter> params = new ArrayList<Parameter>();
     if (aParams != null) {
       for (int i = 0; i < aParams.length / 2; i++) {
-        if (aParams[i * 2 + 1] instanceof ExternalResourceDescription) {
+        if (ExternalResourceFactory.getExternalResourceParameterType(aParams[i * 2 + 1]) != ResourceValueType.NO_RESOURCE) {
           continue;
         }
 
@@ -1097,13 +1099,88 @@ public final class ExternalResourceFacto
       String key = (String) configurationData[i];
       Object value = configurationData[i + 1];
 
+      if (value == null) {
+        continue;
+      }
+      
       // Store External Resource parameters separately
-      if (value instanceof ExternalResourceDescription) {
+      ResourceValueType type = getExternalResourceParameterType(value);
+      if (type == ResourceValueType.PRIMITIVE) {
         ExternalResourceDescription description = (ExternalResourceDescription) value;
         extRes.put(key, description);
       }
+      else if (type.isMultiValued()) {
+        Collection<ExternalResourceDescription> resList;
+        if (type == ResourceValueType.ARRAY) {
+          resList = asList((ExternalResourceDescription[]) value);
+        }
+        else {
+          resList = (Collection<ExternalResourceDescription>) value;
+        }
+
+        // Record the list elements
+        List<Object> params = new ArrayList<Object>();
+        params.add(ResourceList.PARAM_SIZE);
+        params.add(String.valueOf(resList.size())); // "Resource" only supports String parameters!
+        int n = 0;
+        for (ExternalResourceDescription res : resList) {
+          params.add(ResourceList.ELEMENT_KEY + "[" + n + "]");
+          params.add(res);
+          n++;
+        }
+        
+        // Record the list and attach the list elements to the list
+        extRes.put(key, createExternalResourceDescription(ResourceList.class, params.toArray()));
+      }
     }
 
     return extRes;
   }
+  
+  /**
+   * Determine which kind of external resource the given value is. This is only meant for
+   * uimaFIT internal use. This method is required by the ConfigurationParameterFactory, so it is
+   * package private instead of private.
+   */
+  static ResourceValueType getExternalResourceParameterType(Object aValue)
+  {
+    if (aValue == null) {
+      return ResourceValueType.NO_RESOURCE;
+    }
+    
+    boolean isResourcePrimitive = aValue instanceof ExternalResourceDescription;
+    boolean isResourceArray = aValue.getClass().isArray()
+            && ExternalResourceDescription.class.isAssignableFrom(aValue.getClass()
+                    .getComponentType());
+    boolean isResourceCollection = (Collection.class.isAssignableFrom(aValue
+            .getClass()) && !((Collection) aValue).isEmpty() && ((Collection) aValue)
+            .iterator().next() instanceof ExternalResourceDescription);
+    if (isResourcePrimitive) {
+      return ResourceValueType.PRIMITIVE;
+    }
+    else if (isResourceArray) {
+      return ResourceValueType.ARRAY;
+    }
+    else if (isResourceCollection) {
+      return ResourceValueType.COLLECTION;
+    }
+    else {
+      return ResourceValueType.NO_RESOURCE;
+    }
+  }
+  
+  /**
+   * Types of external resource values.
+   */
+  static enum ResourceValueType {
+    NO_RESOURCE,
+    PRIMITIVE,
+    ARRAY,
+    COLLECTION;
+    
+    public boolean isMultiValued()
+    {
+      return this == COLLECTION || this == ARRAY;
+    }
+  }
 }

Added: uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/internal/ResourceList.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/internal/ResourceList.java?rev=1488594&view=auto
==============================================================================
--- uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/internal/ResourceList.java (added)
+++ uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/internal/ResourceList.java Sat Jun  1 20:38:58 2013
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.uima.fit.internal;
+
+import org.apache.uima.fit.component.Resource_ImplBase;
+import org.apache.uima.fit.descriptor.ConfigurationParameter;
+import org.apache.uima.fit.descriptor.ExternalResource;
+
+/**
+ * INTERNAL API - Helper resource used when an {@link ExternalResource} annotation is used on an
+ * array or collection field. 
+ */
+public class ResourceList extends Resource_ImplBase {
+  public static final String ELEMENT_KEY = "ELEMENT";
+  
+  public static final String PARAM_SIZE = "size";
+  @ConfigurationParameter(name = PARAM_SIZE, mandatory = true)
+  private int size;
+
+  public ResourceList() {
+    // Nothing to do
+  }
+  
+  public int getSize() {
+    return size;
+  }
+}

Propchange: uima/sandbox/uimafit/trunk/uimafit/src/main/java/org/apache/uima/fit/internal/ResourceList.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: uima/sandbox/uimafit/trunk/uimafit/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uimafit/trunk/uimafit/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java?rev=1488594&r1=1488593&r2=1488594&view=diff
==============================================================================
--- uima/sandbox/uimafit/trunk/uimafit/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java (original)
+++ uima/sandbox/uimafit/trunk/uimafit/src/test/java/org/apache/uima/fit/factory/ExternalResourceFactoryTest.java Sat Jun  1 20:38:58 2013
@@ -159,7 +159,7 @@ public class ExternalResourceFactoryTest
 
   @Test
   public void testMultiBinding() throws Exception {
-    ExternalResourceDescription extDesc = createExternalResourceDescription(DummyResource.class);
+    ExternalResourceDescription extDesc = createExternalResourceDescription(ResourceWithAssert.class);
 
     // Binding external resource to each Annotator individually
     AnalysisEngineDescription aed1 = createPrimitiveDescription(MultiBindAE.class,
@@ -177,9 +177,101 @@ public class ExternalResourceFactoryTest
     // Check the external resource was injected
     SimplePipeline.runPipeline(CasCreationUtils.createCas(aaed.getAnalysisEngineMetaData()), aaed);
   }
+  
+  /**
+   * Test resource list.
+   */
+  @Test
+  public void testMultiValue() throws Exception {
+    ExternalResourceDescription extDesc1 = createExternalResourceDescription(ResourceWithAssert.class);
+    ExternalResourceDescription extDesc2 = createExternalResourceDescription(ResourceWithAssert.class);
+
+    AnalysisEngineDescription aed = createPrimitiveDescription(MultiValuedResourceAE.class,
+            MultiValuedResourceAE.RES_RESOURCE_ARRAY, asList(extDesc1, extDesc2));
+    
+    AnalysisEngine ae = createAggregate(aed);
+    ae.process(ae.newJCas());
+    ae.collectionProcessComplete();
+  }
+
+  /**
+   * Test sharing a resource list between two AEs on the same aggregate.
+   */
+  @Test
+  public void testMultiValue2() throws Exception {
+    MultiValuedResourceAE.resources.clear();
+    
+    ExternalResourceDescription extDesc1 = createExternalResourceDescription(ResourceWithAssert.class);
+    ExternalResourceDescription extDesc2 = createExternalResourceDescription(ResourceWithAssert.class);
+
+    AnalysisEngineDescription aed = createAggregateDescription(
+            createPrimitiveDescription(MultiValuedResourceAE.class,
+                    MultiValuedResourceAE.RES_RESOURCE_ARRAY, asList(extDesc1, extDesc2)),
+            createPrimitiveDescription(MultiValuedResourceAE.class,
+                    MultiValuedResourceAE.RES_RESOURCE_ARRAY, asList(extDesc1, extDesc2)));
+    
+    AnalysisEngine ae = createAggregate(aed);
+    ae.process(ae.newJCas());
+    
+    // Check that the shared resources are really the same
+    assertEquals(MultiValuedResourceAE.resources.get(0), MultiValuedResourceAE.resources.get(2));
+    assertEquals(MultiValuedResourceAE.resources.get(1), MultiValuedResourceAE.resources.get(3));
+  }
+
+  /**
+   * Test sharing a resource list across aggregates.
+   */
+  @Test
+  public void testMultiValue3() throws Exception {
+    MultiValuedResourceAE.resources.clear();
+    
+    ExternalResourceDescription extDesc1 = createExternalResourceDescription(ResourceWithAssert.class);
+    ExternalResourceDescription extDesc2 = createExternalResourceDescription(ResourceWithAssert.class);
+
+    AnalysisEngineDescription aed = createAggregateDescription(
+            createPrimitiveDescription(MultiValuedResourceAE.class,
+                    MultiValuedResourceAE.RES_RESOURCE_ARRAY, asList(extDesc1, extDesc2)),
+            createAggregateDescription(createPrimitiveDescription(MultiValuedResourceAE.class,
+                    MultiValuedResourceAE.RES_RESOURCE_ARRAY, asList(extDesc1, extDesc2))));
+    
+    AnalysisEngine ae = createAggregate(aed);
+    ae.process(ae.newJCas());
+
+    // Check that the shared resources are really the same
+    assertEquals(MultiValuedResourceAE.resources.get(0), MultiValuedResourceAE.resources.get(2));
+    assertEquals(MultiValuedResourceAE.resources.get(1), MultiValuedResourceAE.resources.get(3));
+  }
+
+  /**
+   * Test nested resource lists.
+   */
+  @Test
+  public void testMultiValue4() throws Exception {
+    ExternalResourceDescription extDesc1 = createExternalResourceDescription(ResourceWithAssert.class);
+    ExternalResourceDescription extDesc2 = createExternalResourceDescription(ResourceWithAssert.class);
+    
+    ExternalResourceDescription extDesc3 = createExternalResourceDescription(ResourceWithAssert.class);
+    ExternalResourceDescription extDesc4 = createExternalResourceDescription(ResourceWithAssert.class);
+
+    ExternalResourceDescription mv1 = createExternalResourceDescription(MultiValuedResource.class,
+            MultiValuedResource.RES_RESOURCE_LIST, new ExternalResourceDescription[] { extDesc1,
+                extDesc2 });
+
+    ExternalResourceDescription mv2 = createExternalResourceDescription(MultiValuedResource.class,
+            MultiValuedResource.RES_RESOURCE_LIST, new ExternalResourceDescription[] { extDesc3,
+                extDesc4 });
 
+    AnalysisEngineDescription aed = createPrimitiveDescription(MultiValuedResourceAE.class,
+            MultiValuedResourceAE.RES_RESOURCE_ARRAY, asList(mv1, mv2));
+    
+    AnalysisEngine ae = createAggregate(aed);
+    ae.process(ae.newJCas());
+    ae.collectionProcessComplete();
+  }
+  
+  
   private static void bindResources(AnalysisEngineDescription desc) throws Exception {
-    bindResource(desc, DummyResource.class);
+    bindResource(desc, ResourceWithAssert.class);
     bindResource(desc, DummyAE.RES_KEY_1, ConfigurableResource.class,
             ConfigurableResource.PARAM_VALUE, "1");
     bindResource(desc, DummyAE.RES_KEY_2, ConfigurableResource.class,
@@ -203,7 +295,7 @@ public class ExternalResourceFactoryTest
 
   public static class DummyAE extends JCasAnnotator_ImplBase {
     @ExternalResource
-    DummyResource r;
+    ResourceWithAssert r;
 
     static final String RES_KEY_1 = "Key1";
 
@@ -306,6 +398,64 @@ public class ExternalResourceFactoryTest
     }
   }
 
+  public static final class MultiValuedResourceAE extends org.apache.uima.fit.component.JCasAnnotator_ImplBase {
+    static final String RES_RESOURCE_ARRAY = "resourceArray";
+    @ExternalResource(key = RES_RESOURCE_ARRAY)
+    ResourceWithAssert[] resourceArray;
+
+    public static List<ResourceWithAssert> resources = new ArrayList<ResourceWithAssert>();
+    
+    @Override
+    public void process(JCas aJCas) throws AnalysisEngineProcessException {
+      assertNotNull("Resource array is null", resourceArray);
+      assertEquals(2, resourceArray.length);
+      assertTrue("Resource array element 0 is not a DummyResource",
+              resourceArray[0] instanceof ResourceWithAssert);
+      assertTrue("Resource array element 1 is not a DummyResource",
+              resourceArray[1] instanceof ResourceWithAssert);
+      assertTrue(resourceArray[0] != resourceArray[1]);
+      
+      resources.add(resourceArray[0]);
+      resources.add(resourceArray[1]);
+      
+      System.out.printf("Element object 0: %d%n", resourceArray[0].hashCode());
+      System.out.printf("Element object 1: %d%n", resourceArray[1].hashCode());
+      
+      for (ResourceWithAssert res : resourceArray) {
+        res.doAsserts();
+      }
+    }
+  }
+
+  public static final class MultiValuedResource extends ResourceWithAssert {
+    static final String RES_RESOURCE_LIST = "resourceList";
+    @ExternalResource(key = RES_RESOURCE_LIST)
+    List<ResourceWithAssert> resourceList;
+
+    public static List<ResourceWithAssert> resources = new ArrayList<ResourceWithAssert>();
+    
+    @Override
+    public void doAsserts() {
+      assertNotNull("Resource array is null", resourceList);
+      assertEquals(2, resourceList.size());
+      assertTrue("Resource array element 0 is not a MultiValuedResourceAE",
+              resourceList.get(0) instanceof ResourceWithAssert);
+      assertTrue("Resource array element 1 is not a MultiValuedResourceAE",
+              resourceList.get(1) instanceof ResourceWithAssert);
+      assertTrue(resourceList.get(0) != resourceList.get(1));
+      
+      resources.add(resourceList.get(0));
+      resources.add(resourceList.get(1));
+      
+      System.out.printf("Element object 0: %d%n", resourceList.get(0).hashCode());
+      System.out.printf("Element object 1: %d%n", resourceList.get(1).hashCode());
+      
+      for (ResourceWithAssert res : resourceList) {
+        res.doAsserts();
+      }
+    }
+  }
+
   /**
    * Example annotator that uses the share model object. In the process() we only test if the model
    * was properly initialized by uimaFIT
@@ -316,7 +466,7 @@ public class ExternalResourceFactoryTest
     static final String RES_KEY = "Res";
 
     @ExternalResource(key = RES_KEY)
-    DummyResource res;
+    ResourceWithAssert res;
 
     @Override
     public void process(JCas aJCas) throws AnalysisEngineProcessException {
@@ -334,8 +484,10 @@ public class ExternalResourceFactoryTest
     }
   }
 
-  public static final class DummyResource extends Resource_ImplBase {
-    // Nothing
+  public static class ResourceWithAssert extends Resource_ImplBase {
+    public void doAsserts() {
+      // Nothing by default
+    }
   }
 
   public static final class ConfigurableResource extends Resource_ImplBase {