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:47 UTC

[uima-uimafit] branch feature/UIMA-6169-Support-Charset-typed-parameters-in-components created (now 80412a6)

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

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


      at 80412a6  [UIMA-6169] Support Charset-typed parameters in components

This branch includes the following new commits:

     new 80412a6  [UIMA-6169] Support Charset-typed parameters in components

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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

Posted by re...@apache.org.
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>