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 2020/02/02 22:00:48 UTC

[uima-uimafit] 01/01: [UIMA-6169] Support Charset-typed parameters in components

This is an automated email from the ASF dual-hosted git repository.

rec pushed a commit to branch feature/UIMA-6169-Support-Charset-typed-parameters-in-components
in repository https://gitbox.apache.org/repos/asf/uima-uimafit.git

commit 80412a64bed7c9c5cdb1e075a5d47186871a1113
Author: Richard Eckart de Castilho <re...@apache.org>
AuthorDate: Sun Feb 2 23:00:34 2020 +0100

    [UIMA-6169] Support Charset-typed parameters in components
    
    - New set of unit tests, including for Charset, URI and URL
    - Improved documentation
    - New converter for Charset parameter values
---
 uimafit-core/pom.xml                               |   6 +
 .../ConfigurationParameterInitializer.java         |  74 ++--
 ...{PropertyEditorUtil.java => ChatsetEditor.java} |  29 +-
 .../propertyeditors/PropertyEditorUtil.java        |   3 +
 .../ConfigurationParameterInitializerTest.java     | 385 ++++++++++++++++++++-
 .../tools.uimafit.configurationparameters.xml      |  21 +-
 6 files changed, 465 insertions(+), 53 deletions(-)

diff --git a/uimafit-core/pom.xml b/uimafit-core/pom.xml
index ba72d05..2e78eee 100644
--- a/uimafit-core/pom.xml
+++ b/uimafit-core/pom.xml
@@ -62,6 +62,12 @@
       <artifactId>spring-beans</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-collections4</artifactId>
+      <version>4.4</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-test</artifactId>
       <scope>test</scope>
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializer.java b/uimafit-core/src/main/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializer.java
index 059b169..81ff354 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializer.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializer.java
@@ -18,6 +18,21 @@
  */
 package org.apache.uima.fit.component.initialize;
 
+import static org.apache.uima.UIMAFramework.getLogger;
+import static org.apache.uima.UIMAFramework.newConfigurationManager;
+import static org.apache.uima.UIMAFramework.newUimaContext;
+import static org.apache.uima.fit.factory.ConfigurationParameterFactory.createConfigurationData;
+import static org.apache.uima.fit.factory.ConfigurationParameterFactory.getConfigurationParameterName;
+import static org.apache.uima.fit.factory.ConfigurationParameterFactory.getDefaultValue;
+import static org.apache.uima.fit.factory.ConfigurationParameterFactory.getParameterSettings;
+import static org.apache.uima.fit.factory.ConfigurationParameterFactory.isConfigurationParameterField;
+import static org.apache.uima.fit.internal.ReflectionUtil.getAnnotation;
+import static org.apache.uima.fit.internal.ReflectionUtil.getFields;
+import static org.apache.uima.fit.internal.ResourceManagerFactory.newResourceManager;
+import static org.apache.uima.fit.internal.propertyeditors.PropertyEditorUtil.registerUimaFITEditors;
+import static org.springframework.beans.PropertyAccessorUtils.canonicalPropertyName;
+import static org.springframework.util.ObjectUtils.isEmpty;
+
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -25,14 +40,11 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.apache.uima.UIMAFramework;
 import org.apache.uima.UimaContext;
 import org.apache.uima.UimaContextAdmin;
 import org.apache.uima.fit.descriptor.ConfigurationParameter;
 import org.apache.uima.fit.factory.ConfigurationParameterFactory;
-import org.apache.uima.fit.internal.ReflectionUtil;
-import org.apache.uima.fit.internal.ResourceManagerFactory;
-import org.apache.uima.fit.internal.propertyeditors.PropertyEditorUtil;
+import org.apache.uima.fit.factory.ConfigurationParameterFactory.ConfigurationData;
 import org.apache.uima.resource.ConfigurationManager;
 import org.apache.uima.resource.CustomResourceSpecifier;
 import org.apache.uima.resource.DataResource;
@@ -45,20 +57,14 @@ import org.apache.uima.resource.metadata.ConfigurationParameterSettings;
 import org.apache.uima.resource.metadata.NameValuePair;
 import org.apache.uima.resource.metadata.ResourceMetaData;
 import org.springframework.beans.MutablePropertyValues;
-import org.springframework.beans.PropertyAccessorUtils;
 import org.springframework.beans.PropertyValue;
-import org.springframework.util.ObjectUtils;
 import org.springframework.validation.DataBinder;
 import org.springframework.validation.ObjectError;
 
 /**
- * <p>
  * Initialize an instance of a class with fields that are annotated as
  * {@link ConfigurationParameter}s from the parameter values given in a {@link UimaContext}.
- * </p>
- * 
  */
-
 public final class ConfigurationParameterInitializer {
 
   private ConfigurationParameterInitializer() {
@@ -89,15 +95,15 @@ public final class ConfigurationParameterInitializer {
   public static void initialize(final Object component, final UimaContext context)
           throws ResourceInitializationException {
     MutablePropertyValues values = new MutablePropertyValues();
-    List<String> mandatoryValues = new ArrayList<String>();
+    List<String> mandatoryValues = new ArrayList<>();
 
-    for (Field field : ReflectionUtil.getFields(component)) { // component.getClass().getDeclaredFields())
-      if (ConfigurationParameterFactory.isConfigurationParameterField(field)) {
-        org.apache.uima.fit.descriptor.ConfigurationParameter annotation = ReflectionUtil
-                .getAnnotation(field, org.apache.uima.fit.descriptor.ConfigurationParameter.class);
+    for (Field field : getFields(component)) { // component.getClass().getDeclaredFields())
+      if (isConfigurationParameterField(field)) {
+        org.apache.uima.fit.descriptor.ConfigurationParameter annotation = getAnnotation(field,
+                org.apache.uima.fit.descriptor.ConfigurationParameter.class);
 
         Object parameterValue;
-        String parameterName = ConfigurationParameterFactory.getConfigurationParameterName(field);
+        String parameterName = getConfigurationParameterName(field);
 
         // Obtain either from the context - or - if the context does not provide the
         // parameter, check if there is a default value. Note there are three possibilities:
@@ -110,7 +116,7 @@ public final class ConfigurationParameterInitializer {
         // value.
         parameterValue = context.getConfigParameterValue(parameterName);
         if (parameterValue == null) {
-          parameterValue = ConfigurationParameterFactory.getDefaultValue(field);
+          parameterValue = getDefaultValue(field);
         }
 
         if (parameterValue != null) {
@@ -129,12 +135,11 @@ public final class ConfigurationParameterInitializer {
       @Override
       protected void checkRequiredFields(MutablePropertyValues mpvs) {
         String[] requiredFields = getRequiredFields();
-        if (!ObjectUtils.isEmpty(requiredFields)) {
-          Map<String, PropertyValue> propertyValues = new HashMap<String, PropertyValue>();
+        if (!isEmpty(requiredFields)) {
+          Map<String, PropertyValue> propertyValues = new HashMap<>();
           PropertyValue[] pvs = mpvs.getPropertyValues();
           for (PropertyValue pv : pvs) {
-            String canonicalName = PropertyAccessorUtils.canonicalPropertyName(pv.getName());
-            propertyValues.put(canonicalName, pv);
+            propertyValues.put(canonicalPropertyName(pv.getName()), pv);
           }
           for (String field : requiredFields) {
             PropertyValue pv = propertyValues.get(field);
@@ -166,9 +171,11 @@ public final class ConfigurationParameterInitializer {
       }
     };
     binder.initDirectFieldAccess();
-    PropertyEditorUtil.registerUimaFITEditors(binder);
+    registerUimaFITEditors(binder);
     binder.setRequiredFields(mandatoryValues.toArray(new String[mandatoryValues.size()]));
+    
     binder.bind(values);
+    
     if (binder.getBindingResult().hasErrors()) {
       StringBuilder sb = new StringBuilder();
       sb.append("Errors initializing [" + component.getClass() + "]");
@@ -200,9 +207,8 @@ public final class ConfigurationParameterInitializer {
     if (component instanceof Resource) {
       context = ((Resource) component).getUimaContextAdmin();
     } else {
-      ResourceManager resMgr = ResourceManagerFactory.newResourceManager();
-      context = UIMAFramework.newUimaContext(UIMAFramework.getLogger(), resMgr,
-              UIMAFramework.newConfigurationManager());
+      ResourceManager resMgr = newResourceManager();
+      context = newUimaContext(getLogger(), resMgr, newConfigurationManager());
     }
 
     ConfigurationManager cfgMgr = context.getConfigurationManager();
@@ -228,7 +234,7 @@ public final class ConfigurationParameterInitializer {
    */
   public static void initialize(Object component, ResourceSpecifier spec)
           throws ResourceInitializationException {
-    initialize(component, ConfigurationParameterFactory.getParameterSettings(spec));
+    initialize(component, getParameterSettings(spec));
   }
 
   /**
@@ -244,7 +250,7 @@ public final class ConfigurationParameterInitializer {
    */
   public static void initialize(Object component, Parameter... parameters)
           throws ResourceInitializationException {
-    Map<String, Object> params = new HashMap<String, Object>();
+    Map<String, Object> params = new HashMap<>();
     for (Parameter p : parameters) {
       params.put(p.getName(), p.getValue());
     }
@@ -264,7 +270,7 @@ public final class ConfigurationParameterInitializer {
    */
   public static void initialize(Object component, NameValuePair... parameters)
           throws ResourceInitializationException {
-    Map<String, Object> params = new HashMap<String, Object>();
+    Map<String, Object> params = new HashMap<>();
     for (NameValuePair p : parameters) {
       params.put(p.getName(), p.getValue());
     }
@@ -288,4 +294,16 @@ public final class ConfigurationParameterInitializer {
     ConfigurationParameterSettings settings = metaData.getConfigurationParameterSettings();
     initialize(component, settings.getParameterSettings());
   }
+  
+  public static void initialize(Object component, Object... aParameters)
+          throws ResourceInitializationException {
+    ConfigurationData configurationData = createConfigurationData(aParameters);
+    Map<String, Object> params = new HashMap<>();
+    for (int i = 0; i < configurationData.configurationParameters.length; i++) {
+      String name = configurationData.configurationParameters[i].getName();
+      Object value = configurationData.configurationValues[i];
+      params.put(name, value);
+    }
+    initialize(component, params);
+  }
 }
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java b/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/ChatsetEditor.java
similarity index 53%
copy from uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java
copy to uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/ChatsetEditor.java
index 97f13f0..0add339 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/ChatsetEditor.java
@@ -18,29 +18,24 @@
  */
 package org.apache.uima.fit.internal.propertyeditors;
 
-import java.util.LinkedList;
-import java.util.Locale;
-
-import org.springframework.beans.PropertyEditorRegistry;
-import org.springframework.beans.propertyeditors.CustomCollectionEditor;
+import java.beans.PropertyEditorSupport;
+import java.nio.charset.Charset;
 
 /**
  * INTERNAL API
+ * 
+ * Custom property editor for {@link Charset}.
  */
-public final class PropertyEditorUtil {
+public class ChatsetEditor extends PropertyEditorSupport {
 
-  private PropertyEditorUtil() {
-    // Utility class
+  @Override
+  public void setAsText(String text) {
+    setValue(Charset.forName(text));
   }
 
-  /**
-   * Register the property editors provided by uimaFIT in the given property editor registry.
-   * 
-   * @param aRegistry a property editor registry
-   */
-  public static void registerUimaFITEditors(PropertyEditorRegistry aRegistry) {
-    aRegistry.registerCustomEditor(Locale.class, new LocaleEditor());
-    aRegistry.registerCustomEditor(String.class, new GetAsTextStringEditor(aRegistry));
-    aRegistry.registerCustomEditor(LinkedList.class, new CustomCollectionEditor(LinkedList.class));
+  @Override
+  public String getAsText() {
+    Object value = getValue();
+    return (value != null ? value.toString() : "");
   }
 }
diff --git a/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java b/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java
index 97f13f0..88a07f5 100644
--- a/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java
+++ b/uimafit-core/src/main/java/org/apache/uima/fit/internal/propertyeditors/PropertyEditorUtil.java
@@ -18,10 +18,12 @@
  */
 package org.apache.uima.fit.internal.propertyeditors;
 
+import java.nio.charset.Charset;
 import java.util.LinkedList;
 import java.util.Locale;
 
 import org.springframework.beans.PropertyEditorRegistry;
+import org.springframework.beans.propertyeditors.CharsetEditor;
 import org.springframework.beans.propertyeditors.CustomCollectionEditor;
 
 /**
@@ -39,6 +41,7 @@ public final class PropertyEditorUtil {
    * @param aRegistry a property editor registry
    */
   public static void registerUimaFITEditors(PropertyEditorRegistry aRegistry) {
+    aRegistry.registerCustomEditor(Charset.class, new CharsetEditor());
     aRegistry.registerCustomEditor(Locale.class, new LocaleEditor());
     aRegistry.registerCustomEditor(String.class, new GetAsTextStringEditor(aRegistry));
     aRegistry.registerCustomEditor(LinkedList.class, new CustomCollectionEditor(LinkedList.class));
diff --git a/uimafit-core/src/test/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializerTest.java b/uimafit-core/src/test/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializerTest.java
index 5784a05..8de2de4 100644
--- a/uimafit-core/src/test/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializerTest.java
+++ b/uimafit-core/src/test/java/org/apache/uima/fit/component/initialize/ConfigurationParameterInitializerTest.java
@@ -18,7 +18,14 @@
  */
 package org.apache.uima.fit.component.initialize;
 
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_16;
+import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.Arrays.asList;
+import static java.util.regex.Pattern.compile;
+import static org.apache.commons.collections4.SetUtils.unmodifiableSet;
+import static org.apache.uima.fit.component.initialize.ConfigurationParameterInitializer.initialize;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -31,8 +38,14 @@ import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.Charset;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.uima.UIMAException;
 import org.apache.uima.UIMAFramework;
@@ -53,11 +66,377 @@ import org.apache.uima.resource.metadata.impl.ConfigurationParameterSettings_imp
 import org.junit.Test;
 import org.xml.sax.SAXException;
 
-/**
- */
-
 public class ConfigurationParameterInitializerTest extends ComponentTestBase {
 
+  public static class PrimitiveTypesInjection {
+    private @ConfigurationParameter int intValue;
+    private @ConfigurationParameter boolean booleanValue;
+    private @ConfigurationParameter String stringValue;
+    private @ConfigurationParameter float floatValue;
+    private @ConfigurationParameter double doubleValue;
+  }
+  
+  @Test
+  public void thatPrimitiveTypesCanBeInjected() throws Exception {
+    PrimitiveTypesInjection target = new PrimitiveTypesInjection();
+    
+    initialize(target,
+            "intValue", 1,
+            "booleanValue", true,
+            "stringValue", "test",
+            "floatValue", 1.234f,
+            "doubleValue", 1.234d);
+    
+    assertThat(target.intValue).isEqualTo(1);
+    assertThat(target.booleanValue).isEqualTo(true);
+    assertThat(target.stringValue).isEqualTo("test");
+    assertThat(target.floatValue).isEqualTo(1.234f);
+    assertThat(target.doubleValue).isEqualTo(1.234d);
+  }
+  
+  public static class PrimitiveArraysInjection {
+    private @ConfigurationParameter int[] intValues;
+    private @ConfigurationParameter boolean[] booleanValues;
+    private @ConfigurationParameter String[] stringValues;
+    private @ConfigurationParameter float[] floatValues;
+    private @ConfigurationParameter double[] doubleValues;
+  }
+  
+  @Test
+  public void thatPrimitiveArraysCanBeInjected() throws Exception {
+    PrimitiveArraysInjection target = new PrimitiveArraysInjection();
+    
+    initialize(target,
+            "intValues", new int[] {1, 2, 3},
+            "booleanValues", new boolean[] {true, false, true},
+            "stringValues", new String[] { "test1", "test2", "test3" },
+            "floatValues", new float[] { 1.234f, 2.468f, 3.456f },
+            "doubleValues", new double[] { 1.234d, 2.468d, 3.456d });
+    
+    assertThat(target.intValues).containsExactly(1,2,3);
+    assertThat(target.booleanValues).containsExactly(true, false, true);
+    assertThat(target.stringValues).containsExactly("test1", "test2", "test3");
+    assertThat(target.floatValues).containsExactly(1.234f, 2.468f, 3.456f);
+    assertThat(target.doubleValues).containsExactly(1.234d, 2.468d, 3.456d);
+  }
+  
+  @Test
+  public void thatPrimitiveArraysCanBeInjectedAsLists() throws Exception {
+    PrimitiveArraysInjection target = new PrimitiveArraysInjection();
+    
+    initialize(target,
+            "intValues", asList(1, 2, 3),
+            "booleanValues", asList(true, false, true),
+            "stringValues", asList("test1", "test2", "test3"),
+            "floatValues", asList(1.234f, 2.468f, 3.456f),
+            "doubleValues", asList(1.234d, 2.468d, 3.456d));
+    
+    assertThat(target.intValues).containsExactly(1,2,3);
+    assertThat(target.booleanValues).containsExactly(true, false, true);
+    assertThat(target.stringValues).containsExactly("test1", "test2", "test3");
+    assertThat(target.floatValues).containsExactly(1.234f, 2.468f, 3.456f);
+    assertThat(target.doubleValues).containsExactly(1.234d, 2.468d, 3.456d);
+  }
+  
+  @Test
+  public void thatPrimitiveArraysCanBeInjectedAsValues() throws Exception {
+    PrimitiveArraysInjection target = new PrimitiveArraysInjection();
+    
+    initialize(target,
+            "intValues", 1,
+            "booleanValues", true,
+            "stringValues", "test",
+            "floatValues", 1.234f,
+            "doubleValues", 1.234d);
+    
+    assertThat(target.intValues).containsExactly(1);
+    assertThat(target.booleanValues).containsExactly(true);
+    assertThat(target.stringValues).containsExactly("test");
+    assertThat(target.floatValues).containsExactly(1.234f);
+    assertThat(target.doubleValues).containsExactly(1.234d);
+  }
+  
+  public static class FileInjection {
+    private @ConfigurationParameter File file;
+    private @ConfigurationParameter File fileFromString;
+    private @ConfigurationParameter File[] fileArray;
+    private @ConfigurationParameter File[] fileArrayFromString;
+    private @ConfigurationParameter List<File> fileList;
+    private @ConfigurationParameter List<File> fileFromStringList;
+    private @ConfigurationParameter Set<File> fileSet;
+  }
+  
+  @Test
+  public void thatFileObjectCanBeInjected() throws Exception {
+    FileInjection target = new FileInjection();
+    
+    initialize(target,
+            "file", new File("test"),
+            "fileFromString", "test",
+            "fileArray", new File[] {new File("test1"), new File("test2") },
+            "fileArrayFromString", new String[] {"test1", "test2"},
+            "fileList", asList(new File("test1"), new File("test2")),
+            "fileSet", unmodifiableSet(new File("test1"), new File("test2")),
+            "fileFromStringList", asList("test1", "test2"));
+    
+    assertThat(target.file).hasName("test");
+    assertThat(target.fileFromString).hasName("test");
+    assertThat(target.fileArray).extracting(File::getName).containsExactly("test1", "test2");
+    assertThat(target.fileArrayFromString).extracting(File::getName).containsExactly("test1",
+            "test2");
+    assertThat(target.fileList).extracting(File::getName).containsExactly("test1", "test2");
+    assertThat(target.fileFromStringList).extracting(File::getName).containsExactly(
+            "test1", "test2");
+    assertThat(target.fileSet).extracting(File::getName).containsExactlyInAnyOrder(
+            "test1", "test2");
+  }
+  
+  public static class ClassInjection {
+    private @ConfigurationParameter Class<?> clazz;
+    private @ConfigurationParameter Class<?> clazzFromString;
+    private @ConfigurationParameter Class<?>[] clazzArray;
+    private @ConfigurationParameter Class<?>[] clazzArrayFromString;
+    private @ConfigurationParameter List<Class<?>> clazzList;
+    private @ConfigurationParameter List<Class<?>> clazzListFromString;
+    private @ConfigurationParameter Set<Class<?>> clazzSet;
+  }
+  
+  @Test
+  public void thatClassObjectCanBeInjected() throws Exception {
+    ClassInjection target = new ClassInjection();
+    
+    initialize(target,
+            "clazz", Integer.class,
+            "clazzFromString", Integer.class.getName(),
+            "clazzArray", new Class<?>[] { Integer.class, Boolean.class, Float.class },
+            "clazzArrayFromString", new String[] { Integer.class.getName(), Boolean.class.getName(),
+                    Float.class.getName() },
+            "clazzList", asList(Integer.class, Boolean.class, Float.class),
+            "clazzListFromString", asList(Integer.class.getName(), Boolean.class.getName(), 
+                    Float.class.getName()),
+            "clazzSet", unmodifiableSet(Integer.class, Boolean.class, Float.class));
+    
+    assertThat(target.clazz).isEqualTo(Integer.class);
+    assertThat(target.clazzFromString).isEqualTo(Integer.class);
+    assertThat(target.clazzArray).containsExactly(Integer.class, Boolean.class, Float.class);
+    assertThat(target.clazzArrayFromString).containsExactly(Integer.class, Boolean.class,
+            Float.class);
+    assertThat(target.clazzList).containsExactly(Integer.class, Boolean.class, Float.class);
+    assertThat(target.clazzListFromString).containsExactly(Integer.class, Boolean.class,
+            Float.class);
+    assertThat(target.clazzSet).containsExactlyInAnyOrder(Integer.class, Boolean.class,
+            Float.class);
+  }
+  
+  public static class URIInjection {
+    private @ConfigurationParameter URI uri;
+    private @ConfigurationParameter URI uriFromString;
+    private @ConfigurationParameter URI[] uriArray;
+    private @ConfigurationParameter URI[] uriArrayFromString;
+    private @ConfigurationParameter List<URI> uriList;
+    private @ConfigurationParameter List<URI> uriListFromString;
+    private @ConfigurationParameter Set<URI> uriSet;
+  }
+  
+  @Test
+  public void thatURICanBeInjected() throws Exception {
+    URIInjection target = new URIInjection();
+    
+    initialize(target,
+            "uri", URI.create("file:test"),
+            "uriFromString", "file:test",
+            "uriArray", new URI[] { URI.create("file:test1"), URI.create("file:test2"), 
+                    URI.create("file:test3") },
+            "uriArrayFromString", new String[] { "file:test1", "file:test2", "file:test3" },
+            "uriList", asList(URI.create("file:test1"), URI.create("file:test2"), 
+                    URI.create("file:test3")),
+            "uriListFromString", asList("file:test1", "file:test2", "file:test3"),
+            "uriSet", unmodifiableSet(URI.create("file:test1"), URI.create("file:test2"), 
+                    URI.create("file:test3")));
+    
+    assertThat(target.uri).isEqualTo(URI.create("file:test"));
+    assertThat(target.uriFromString).isEqualTo(URI.create("file:test"));
+    assertThat(target.uriArray).containsExactly(URI.create("file:test1"), URI.create("file:test2"), 
+            URI.create("file:test3"));
+    assertThat(target.uriArrayFromString).containsExactly(URI.create("file:test1"), 
+            URI.create("file:test2"), URI.create("file:test3"));
+    assertThat(target.uriList).containsExactly(URI.create("file:test1"), URI.create("file:test2"), 
+            URI.create("file:test3"));
+    assertThat(target.uriListFromString).containsExactly(URI.create("file:test1"), 
+            URI.create("file:test2"), URI.create("file:test3"));
+    assertThat(target.uriSet).containsExactlyInAnyOrder(URI.create("file:test1"), 
+            URI.create("file:test2"), URI.create("file:test3"));
+  }
+  
+  public static class URLInjection {
+    private @ConfigurationParameter URL URL;
+    private @ConfigurationParameter URL URLFromString;
+    private @ConfigurationParameter URL[] URLArray;
+    private @ConfigurationParameter URL[] URLArrayFromString;
+    private @ConfigurationParameter List<URL> URLList;
+    private @ConfigurationParameter List<URL> URLListFromString;
+    private @ConfigurationParameter Set<URL> URLSet;
+  }
+  
+  @Test
+  public void thatURLCanBeInjected() throws Exception {
+    URLInjection target = new URLInjection();
+    
+    initialize(target,
+            "URL", new URL("file:test"),
+            "URLFromString", "file:test",
+            "URLArray", new URL[] { new URL("file:test1"), new URL("file:test2"), 
+                    new URL("file:test3") },
+            "URLArrayFromString", new String[] { "file:test1", "file:test2", "file:test3" },
+            "URLList", asList(new URL("file:test1"), new URL("file:test2"), 
+                    new URL("file:test3")),
+            "URLListFromString", asList("file:test1", "file:test2", "file:test3"),
+            "URLSet", unmodifiableSet(new URL("file:test1"), new URL("file:test2"), 
+                    new URL("file:test3")));
+    
+    assertThat(target.URL).isEqualTo(new URL("file:test"));
+    assertThat(target.URLFromString).isEqualTo(new URL("file:test"));
+    assertThat(target.URLArray).containsExactly(new URL("file:test1"), new URL("file:test2"), 
+            new URL("file:test3"));
+    assertThat(target.URLArrayFromString).containsExactly(new URL("file:test1"), 
+            new URL("file:test2"), new URL("file:test3"));
+    assertThat(target.URLList).containsExactly(new URL("file:test1"), new URL("file:test2"), 
+            new URL("file:test3"));
+    assertThat(target.URLListFromString).containsExactly(new URL("file:test1"), 
+            new URL("file:test2"), new URL("file:test3"));
+    assertThat(target.URLSet).containsExactlyInAnyOrder(new URL("file:test1"), 
+            new URL("file:test2"), new URL("file:test3"));
+  }
+  
+  public static class PatternInjection {
+    private @ConfigurationParameter Pattern pattern;
+    private @ConfigurationParameter Pattern patternFromString;
+    private @ConfigurationParameter Pattern[] patternArray;
+    private @ConfigurationParameter Pattern[] patternArrayFromString;
+    private @ConfigurationParameter List<Pattern> patternList;
+    private @ConfigurationParameter List<Pattern> patternListFromString;
+  }
+  
+  @Test
+  public void thatPatternCanBeInjected() throws Exception {
+    PatternInjection target = new PatternInjection();
+    
+    initialize(target,
+            "pattern", compile("^test$"),
+            "patternFromString", "^test$",
+            "patternArray", new Pattern[] { compile("test1"), compile("test2"), compile("test3") },
+            "patternArrayFromString", new String[] { "test1", "test2", "test3" },
+            "patternList", asList(compile("test1"), compile("test2"), compile("test3")),
+            "patternListFromString", asList("test1", "test2", "test3"));
+    
+    assertThat(target.pattern).matches(p -> p.matcher("test").matches());
+    assertThat(target.patternFromString).matches(p -> p.matcher("test").matches());
+    assertThat(target.patternArray).hasSize(3);
+    assertThat(target.patternArray[0]).matches(p -> p.matcher("test1").matches());
+    assertThat(target.patternArray[1]).matches(p -> p.matcher("test2").matches());
+    assertThat(target.patternArray[2]).matches(p -> p.matcher("test3").matches());
+    assertThat(target.patternArrayFromString).hasSize(3);
+    assertThat(target.patternArrayFromString[0]).matches(p -> p.matcher("test1").matches());
+    assertThat(target.patternArrayFromString[1]).matches(p -> p.matcher("test2").matches());
+    assertThat(target.patternArrayFromString[2]).matches(p -> p.matcher("test3").matches());
+    assertThat(target.patternList).hasSize(3);
+    assertThat(target.patternList.get(0)).matches(p -> p.matcher("test1").matches());
+    assertThat(target.patternList.get(1)).matches(p -> p.matcher("test2").matches());
+    assertThat(target.patternList.get(2)).matches(p -> p.matcher("test3").matches());
+    assertThat(target.patternList).hasSize(3);
+    assertThat(target.patternListFromString.get(0)).matches(p -> p.matcher("test1").matches());
+    assertThat(target.patternListFromString.get(1)).matches(p -> p.matcher("test2").matches());
+    assertThat(target.patternListFromString.get(2)).matches(p -> p.matcher("test3").matches());
+  }  
+
+  public static class CharsetInjection {
+    private @ConfigurationParameter Charset charset;
+    private @ConfigurationParameter String charsetAsString;
+    private @ConfigurationParameter Charset charsetFromString;
+    private @ConfigurationParameter Charset[] charsetArray;
+    private @ConfigurationParameter String[] charsetsAsStringArray;
+    private @ConfigurationParameter Charset[] charsetArrayFromString;
+    private @ConfigurationParameter List<Charset> charsetList;
+    private @ConfigurationParameter List<String> charsetAsStringList;
+    private @ConfigurationParameter List<Charset> charsetListFromString;
+    private @ConfigurationParameter Set<Charset> charsetSet;
+  }
+  
+  @Test
+  public void thatCharsetCanBeInjected() throws Exception {
+    CharsetInjection target = new CharsetInjection();
+    
+    initialize(target,
+            "charset", UTF_8,
+            "charsetAsString", UTF_8,
+            "charsetFromString", UTF_8.toString(),
+            "charsetArray", new Charset[] { UTF_8, UTF_16, US_ASCII },
+            "charsetsAsStringArray", new Charset[] { UTF_8, UTF_16, US_ASCII },
+            "charsetArrayFromString", new String[] { UTF_8.toString(), UTF_16.toString(), 
+                    US_ASCII.toString() },
+            "charsetList", asList(UTF_8, UTF_16, US_ASCII),
+            "charsetAsStringList", asList(UTF_8, UTF_16, US_ASCII),
+            "charsetListFromString", asList(UTF_8.toString(), UTF_16.toString(), 
+                    US_ASCII.toString()),
+            "charsetSet", unmodifiableSet(UTF_8, UTF_16, US_ASCII));
+    
+    assertThat(target.charset).isEqualTo(UTF_8);
+    assertThat(target.charsetAsString).isEqualTo(UTF_8.toString());
+    assertThat(target.charsetFromString).isEqualTo(UTF_8);
+    assertThat(target.charsetArray).containsExactly(UTF_8, UTF_16, US_ASCII);
+    assertThat(target.charsetsAsStringArray).containsExactly(UTF_8.toString(), UTF_16.toString(),
+            US_ASCII.toString());
+    assertThat(target.charsetArrayFromString).containsExactly(UTF_8, UTF_16, US_ASCII);
+    assertThat(target.charsetList).containsExactly(UTF_8, UTF_16, US_ASCII);
+    assertThat(target.charsetAsStringList).containsExactly(UTF_8.toString(), UTF_16.toString(),
+            US_ASCII.toString());
+    assertThat(target.charsetListFromString).containsExactly(UTF_8, UTF_16, US_ASCII);
+    assertThat(target.charsetSet).containsExactlyInAnyOrder(UTF_8, UTF_16, US_ASCII);
+  }
+
+
+  private static class CustomClassWithStringConstructor {
+    private String value;
+    
+    public CustomClassWithStringConstructor(String aValue) {
+      value = aValue;
+    }
+    
+    public String getValue() {
+      return value;
+    }
+  }
+  
+  public static class CustomClassWithStringConstructorInjection {
+    private @ConfigurationParameter CustomClassWithStringConstructor customFromString;
+    private @ConfigurationParameter CustomClassWithStringConstructor[] customArrayFromString;
+    private @ConfigurationParameter List<CustomClassWithStringConstructor> customListFromString;
+  }
+  
+  @Test
+  public void thatCustomClassWithStringConstructorObjectCanBeInjected() throws Exception {
+    CustomClassWithStringConstructorInjection target = 
+            new CustomClassWithStringConstructorInjection();
+    
+    initialize(target,
+            "customFromString", "test",
+            "customArrayFromString", new String[] { "test1", "test2", "test3" },
+            "customListFromString", asList("test1", "test2", "test3"));
+    
+    assertThat(target.customFromString)
+            .extracting(CustomClassWithStringConstructor::getValue)
+            .containsExactly("test");
+    assertThat(target.customArrayFromString)
+            .extracting(CustomClassWithStringConstructor::getValue)
+            .containsExactly("test1", "test2", "test3");
+    assertThat(target.customListFromString)
+            .extracting(CustomClassWithStringConstructor::getValue)
+            .containsExactly("test1", "test2", "test3");
+
+  }
+  
+  // --- Legacy unit tests below ---
+
   @Test
   public void testInitialize() throws ResourceInitializationException, SecurityException {
 
diff --git a/uimafit-docbook/src/docbook/tools.uimafit.configurationparameters.xml b/uimafit-docbook/src/docbook/tools.uimafit.configurationparameters.xml
index 886f746..fd277e4 100644
--- a/uimafit-docbook/src/docbook/tools.uimafit.configurationparameters.xml
+++ b/uimafit-docbook/src/docbook/tools.uimafit.configurationparameters.xml
@@ -166,9 +166,20 @@
   }
 }</programlisting>
   <para>Fields that can be annotated with the <classname>@ConfigurationParameter</classname>
-    annotation are any array or collection types of primitive types (<type>int</type>,
-      <type>boolean</type>, <type>float</type>, <type>double</type>), any enum types, any types that
-    define a constructor accepting a single <classname>String</classname> (e.g.
-      <classname>File</classname>), as well as, fields of the types <classname>Pattern</classname>
-    and <classname>Locale</classname>.</para>
+    annotation are any array or collection types (including if they are only typed via interfaces
+    such as <type>List</type> or <type>Set</type>) of primitive types (<type>int</type>,
+      <type>boolean</type>, <type>float</type>, <type>double</type>). Enum types, as well as, 
+      fields of the types 
+      <classname>Charset</classname>, 
+      <classname>File</classname>, 
+      <classname>Locale</classname>, 
+      <classname>Pattern</classname>,
+      <classname>URI</classname>, and
+      <classname>URL</classname> can also be used. 
+      These can be initialized either using an object value (e.g. <code>StandardChartsets.UTF_8</code>)
+      or a string value (e.g. <code>"UTF-8"</code>).
+      Additionally it is possible to inject any fields of types that define a constructor accepting
+      a single <classname>String</classname>. These must be initialized from a string value.</para>
+  <para>Multi-valued parameters can be initialized from single values without having to wrap these
+      into a container.</para>
 </chapter>