Added @Field Annotation to support auto initilaize params from config

Project: http://git-wip-us.apache.org/repos/asf/tika/repo
Commit: http://git-wip-us.apache.org/repos/asf/tika/commit/aad23d9e
Tree: http://git-wip-us.apache.org/repos/asf/tika/tree/aad23d9e
Diff: http://git-wip-us.apache.org/repos/asf/tika/diff/aad23d9e

Branch: refs/heads/master
Commit: aad23d9e848b8d8e9a5a7a1f4359ef4a2dbdba24
Parents: c6eefbd
Author: Thamme Gowda <[email protected]>
Authored: Wed Jun 1 16:28:23 2016 -0700
Committer: Thamme Gowda <[email protected]>
Committed: Wed Jun 1 16:28:23 2016 -0700

----------------------------------------------------------------------
 .../main/java/org/apache/tika/config/Field.java |  43 +++++
 .../java/org/apache/tika/config/ParamField.java | 167 ++++++++++++++++
 .../java/org/apache/tika/config/TikaConfig.java |   7 +-
 .../org/apache/tika/utils/AnnotationUtils.java  | 131 +++++++++++++
 .../tika/parser/DummyParametrizedParser.java    |  97 ++++++++++
 .../tika/parser/ParametrizedParserTest.java     |  67 +++++++
 .../apache/tika/utils/AnnotationUtilsTest.java  | 190 +++++++++++++++++++
 .../tika/config/TIKA-1986-parametrized.xml      |  37 ++++
 8 files changed, 738 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/main/java/org/apache/tika/config/Field.java
----------------------------------------------------------------------
diff --git a/tika-core/src/main/java/org/apache/tika/config/Field.java 
b/tika-core/src/main/java/org/apache/tika/config/Field.java
new file mode 100644
index 0000000..f4fe3f2
--- /dev/null
+++ b/tika-core/src/main/java/org/apache/tika/config/Field.java
@@ -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.tika.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Field annotation is a contract for binding {@link Param} value from
+ * Tika Configuration to any instance of {@link 
org.apache.tika.base.Configurable}
+ * services
+ * @since Apache Tika 1.14
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+public @interface Field{
+    /**
+     *
+     * @return name of the Field
+     */
+    String name() default ParamField.DEFAULT;
+
+    /**
+     * @return whether this field is required or not
+     */
+    boolean required() default false;
+}

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/main/java/org/apache/tika/config/ParamField.java
----------------------------------------------------------------------
diff --git a/tika-core/src/main/java/org/apache/tika/config/ParamField.java 
b/tika-core/src/main/java/org/apache/tika/config/ParamField.java
new file mode 100644
index 0000000..96063dc
--- /dev/null
+++ b/tika-core/src/main/java/org/apache/tika/config/ParamField.java
@@ -0,0 +1,167 @@
+/*
+ * 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.tika.config;
+
+import java.lang.reflect.*;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * This class stores metdata for {@link Field} annotation are used to map them
+ * to {@link Param} at runtime
+ *
+ * @since Apache Tika 1.14
+ */
+public class ParamField {
+
+    public static final String DEFAULT = "#default";
+
+    //NOTE: since (primitive type) is NOT AssignableFrom (BoxedType),
+    // we just use boxed type for everything!
+    // Example : short.class.isAssignableFrom(Short.class) ? false
+    private static final Map<Class<?>, Class<?>> PRIMITIVE_MAP
+            = new HashMap<Class<?>, Class<?>>(){{
+        put(int.class, Integer.class);
+        put(short.class, Short.class);
+        put(boolean.class, Boolean.class);
+        put(long.class, Long.class);
+        put(float.class, Float.class);
+        put(double.class, Double.class);
+    }};
+
+    private java.lang.reflect.Field field;
+    private Method setter;
+    private String name;
+    private Class<?> type;
+    private boolean required;
+
+    /**
+     * Creates a ParamField object
+     * @param member a field or method which has {@link Field} annotation
+     */
+    public ParamField(AccessibleObject member){
+        if (member instanceof java.lang.reflect.Field) {
+            field = (java.lang.reflect.Field) member;
+        } else {
+            setter = (Method) member;
+        }
+
+        Field annotation = member.getAnnotation(Field.class);
+        required = annotation.required();
+        if (annotation.name().equals(DEFAULT)) {
+            if (field != null){
+                name = field.getName();
+            } else {
+                String funcName = setter.getName();
+                if (funcName.startsWith("set")) {
+                    name = funcName.replaceFirst("^set", "");
+                }
+            }
+        }
+        name = retrieveParamName(annotation);
+        type = retrieveType();
+    }
+
+    public java.lang.reflect.Field getField() {
+        return field;
+    }
+
+    public Method getSetter() {
+        return setter;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class<?> getType() {
+        return type;
+    }
+
+    public boolean isRequired() {
+        return required;
+    }
+
+    /**
+     * Sets given value to the annotated field of bean
+     * @param bean bean with annotation for field
+     * @param value value of field
+     * @throws IllegalAccessException when it occurs
+     * @throws InvocationTargetException when it occurs
+     */
+    public void assignValue(Object bean, Object value)
+            throws IllegalAccessException, InvocationTargetException {
+        if (field != null) {
+            field.set(bean, value);
+        } else {
+            setter.invoke(bean, value);
+        }
+    }
+
+    private Class retrieveType() {
+        Class type;
+        if (field != null) {
+            type = field.getType();
+        } else {
+            Class[] params = setter.getParameterTypes();
+            if (params.length != 1) {
+                //todo:Tika config exception
+                String msg = "Invalid setter method. Must have one and only 
one parameter. ";
+                if (setter.getName().startsWith("get")) {
+                    msg += "Perhaps the annotation is misplaced on " +
+                            setter.getName() +" while a set'X' is expected?";
+                }
+                throw new RuntimeException(msg);
+            }
+            type = params[0];
+        }
+        if (type.isPrimitive() && PRIMITIVE_MAP.containsKey(type)){
+            type = PRIMITIVE_MAP.get(type); //primitive types have hard time
+        }
+        return type;
+    }
+
+    private String retrieveParamName(Field annotation) {
+        String name;
+        if (annotation.name().equals(DEFAULT)) {
+            if (field != null) {
+                name = field.getName();
+            } else {
+                String setterName = setter.getName();
+                if (setterName.startsWith("set") && setterName.length() > 3) {
+                    name = setterName.substring(3, 4).toLowerCase(Locale.ROOT)
+                            + setterName.substring(4);
+                } else {
+                    name = setter.getName();
+                }
+            }
+        } else {
+            name = annotation.name();
+        }
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return "ParamField{" +
+                "name='" + name + '\'' +
+                ", type=" + type +
+                ", required=" + required +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/main/java/org/apache/tika/config/TikaConfig.java
----------------------------------------------------------------------
diff --git a/tika-core/src/main/java/org/apache/tika/config/TikaConfig.java 
b/tika-core/src/main/java/org/apache/tika/config/TikaConfig.java
index 17b735e..853cdf0 100644
--- a/tika-core/src/main/java/org/apache/tika/config/TikaConfig.java
+++ b/tika-core/src/main/java/org/apache/tika/config/TikaConfig.java
@@ -59,6 +59,7 @@ import org.apache.tika.parser.DefaultParser;
 import org.apache.tika.parser.ParseContext;
 import org.apache.tika.parser.Parser;
 import org.apache.tika.parser.ParserDecorator;
+import org.apache.tika.utils.AnnotationUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -567,8 +568,12 @@ public class TikaConfig {
                 loaded = decorate(loaded, element);
                 //if the instance is configurable, then call configure()
                 if (loaded instanceof Configurable){
+                    Map<String, Param<?>> params = getParams(element);
+                    //Assigning the params to bean fields/setters
+                    AnnotationUtils.assignFieldParams(loaded, params);
+                    //invoking the configure() hook
                     ParseContext context = new ParseContext();
-                    context.getParams().putAll(getParams(element));
+                    context.getParams().putAll(params);
                     ((Configurable) loaded).configure(context); // initialize 
here
                 }
                 // All done with setup

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/main/java/org/apache/tika/utils/AnnotationUtils.java
----------------------------------------------------------------------
diff --git a/tika-core/src/main/java/org/apache/tika/utils/AnnotationUtils.java 
b/tika-core/src/main/java/org/apache/tika/utils/AnnotationUtils.java
new file mode 100644
index 0000000..08e004b
--- /dev/null
+++ b/tika-core/src/main/java/org/apache/tika/utils/AnnotationUtils.java
@@ -0,0 +1,131 @@
+/*
+ * 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.tika.utils;
+
+import org.apache.tika.config.Field;
+import org.apache.tika.config.Param;
+import org.apache.tika.config.ParamField;
+import org.apache.tika.config.TikaConfig;
+import org.apache.tika.exception.TikaConfigException;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AccessibleObject;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class contains utilities for dealing with tika annotations
+ * @since Apache Tika 1.14
+ */
+public class AnnotationUtils {
+
+    /**
+     * Cache for annotations for Bean classes which have {@link Field}
+     */
+    private static final Map<Class<?>, List<ParamField>> PARAM_INFO =
+            new HashMap<>();
+
+    /**
+     * Collects all the fields and methods for an annotation
+     * @param clazz bean class with annotations
+     * @param annotation annotation class
+     * @return list of accessible objects such as fields and methods
+     */
+    private static List<AccessibleObject> collectInfo(
+            Class<?> clazz, Class<? extends Annotation> annotation) {
+
+        Class superClazz = clazz;
+        List<AccessibleObject> members = new ArrayList<>();
+        List<AccessibleObject> annotatedMembers = new ArrayList<>();
+        //walk through the inheritance chain
+        while (superClazz != null && superClazz != Object.class) {
+            members.addAll(Arrays.asList(superClazz.getDeclaredFields()));
+            members.addAll(Arrays.asList(superClazz.getDeclaredMethods()));
+            superClazz = superClazz.getSuperclass();
+        }
+
+        for (final AccessibleObject member : members) {
+            if (member.isAnnotationPresent(annotation)) {
+                AccessController.doPrivileged(new PrivilegedAction<Void>(){
+                    @Override
+                    public Void run() {
+                        member.setAccessible(true);
+                        return null;
+                    }
+                });
+                annotatedMembers.add(member);
+            }
+        }
+        return annotatedMembers;
+    }
+
+    /**
+     * Assigns the param values to bean
+     * @throws TikaConfigException when an error occurs while assigning params
+     */
+    public static void assignFieldParams(Object bean, Map<String, Param<?>> 
params) throws TikaConfigException {
+        Class<?> beanClass = bean.getClass();
+        if (!PARAM_INFO.containsKey(beanClass)) {
+            synchronized (TikaConfig.class){
+                if (!PARAM_INFO.containsKey(beanClass)) {
+                    List<AccessibleObject> aObjs = collectInfo(beanClass,
+                            org.apache.tika.config.Field.class);
+                    List<ParamField> fields = new ArrayList<>(aObjs.size());
+
+                    for (AccessibleObject aObj : aObjs) {
+                        fields.add(new ParamField(aObj));
+                    }
+                    PARAM_INFO.put(beanClass, fields);
+                }
+            }
+        }
+
+        List<ParamField> fields = PARAM_INFO.get(beanClass);
+        for (ParamField field : fields) {
+            Param<?> param = params.get(field.getName());
+            if (param != null){
+                if (field.getType().isAssignableFrom(param.getType())) {
+                    try {
+                        field.assignValue(bean, param.getValue());
+                    } catch (Exception e) {
+                        throw new TikaConfigException(e.getMessage(), e);
+                    }
+                } else {
+                    String msg = String.format("Value '%s' of type '%s' cant 
be" +
+                            " assigned to field '%s' of defined type '%s'",
+                            param.getValue(), param.getValue().getClass(),
+                            field.getName(), field.getType());
+                    throw new TikaConfigException(msg);
+                }
+            } else if (field.isRequired()){
+                //param not supplied but field is declared as required?
+                String msg = String.format("Param %s is required for %s," +
+                        " but it is not given in config.", field.getName(),
+                        bean.getClass().getName());
+                throw new TikaConfigException(msg);
+            } else {
+                //FIXME: SLF4j is not showing up for import, fix it and send 
this to LOG.debug
+                //LOG.debug("Param not supplied, field is not mandatory");
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/test/java/org/apache/tika/parser/DummyParametrizedParser.java
----------------------------------------------------------------------
diff --git 
a/tika-core/src/test/java/org/apache/tika/parser/DummyParametrizedParser.java 
b/tika-core/src/test/java/org/apache/tika/parser/DummyParametrizedParser.java
new file mode 100644
index 0000000..383a80b
--- /dev/null
+++ 
b/tika-core/src/test/java/org/apache/tika/parser/DummyParametrizedParser.java
@@ -0,0 +1,97 @@
+/*
+ * 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.tika.parser;
+
+import org.apache.tika.config.Field;
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.mime.MediaType;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A test Parsers to test {@link Field}
+ * @since Apache Tika 1.14
+ */
+public class DummyParametrizedParser extends AbstractParser
+        implements ConfigurableParser {
+
+    private static Set<MediaType> MIMES = new HashSet<>();
+    static {
+        MIMES.add(MediaType.TEXT_PLAIN);
+        MIMES.add(MediaType.TEXT_HTML);
+        MIMES.add(MediaType.APPLICATION_XML);
+        MIMES.add(MediaType.OCTET_STREAM);
+    }
+
+    @Field(name = "testparam") private String testParam;
+    @Field private short xshort;
+    @Field private int xint;
+    @Field private long xlong;
+    @Field(name = "xbigint") private BigInteger xbigInt;
+    @Field private float xfloat;
+    @Field private double xdouble;
+    @Field private boolean xbool;
+    @Field private URL xurl;
+    @Field private URI xuri;
+
+    @Field private String missing = "default";
+
+    private String inner = "inner";
+    private File xfile;
+
+    @Field
+    public void setXfile(File xfile){
+        this.xfile = xfile;
+    }
+
+    @Override
+    public Set<MediaType> getSupportedTypes(ParseContext context) {
+
+        return MIMES;
+    }
+
+    @Override
+    public void parse(InputStream stream, ContentHandler handler,
+                      Metadata metadata, ParseContext context)
+            throws IOException, SAXException, TikaException {
+
+        metadata.add("testparam", testParam);
+        metadata.add("xshort", xshort + "");
+        metadata.add("xint", xint + "");
+        metadata.add("xlong", xlong + "");
+        metadata.add("xbigint", xbigInt + "");
+        metadata.add("xfloat", xfloat + "");
+        metadata.add("xdouble", xdouble + "");
+        metadata.add("xbool", xbool + "");
+        metadata.add("xuri", xuri + "");
+        metadata.add("xurl", xurl + "");
+        metadata.add("xfile", xfile + "");
+
+        metadata.add("inner", inner + "");
+        metadata.add("missing", missing + "");
+    }
+}

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/test/java/org/apache/tika/parser/ParametrizedParserTest.java
----------------------------------------------------------------------
diff --git 
a/tika-core/src/test/java/org/apache/tika/parser/ParametrizedParserTest.java 
b/tika-core/src/test/java/org/apache/tika/parser/ParametrizedParserTest.java
new file mode 100644
index 0000000..290f819
--- /dev/null
+++ b/tika-core/src/test/java/org/apache/tika/parser/ParametrizedParserTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.tika.parser;
+
+import org.apache.tika.Tika;
+import org.apache.tika.config.TikaConfig;
+import org.apache.tika.metadata.Metadata;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ParametrizedParserTest {
+
+    private static final String TIKA_CFG_FILE = 
"org/apache/tika/config/TIKA-1986-parametrized.xml";
+    private static final Map<String, String> expcted = new HashMap<String, 
String>() {
+        {
+            put("testparam", "testparamval");
+            put("xshort", "1000");
+            put("xint", "999999999");
+            put("xlong", "9999999999999");
+            put("xbigint", "99999999999999999999999999999999999999999999999");
+            put("xfloat", "10.2");
+            put("xbool", "true");
+            put("xdouble", "4.6");
+            put("xurl", "http://apache.org";);
+            put("xfile", "/");
+            put("xuri", "tika://customuri?param=value");
+
+            put("inner", "inner");
+            put("missing", "default");
+        }
+    };
+
+
+    @Test
+    public void testConfigurableParserTypes() throws Exception {
+        URL configFileUrl = 
getClass().getClassLoader().getResource(TIKA_CFG_FILE);
+        assert configFileUrl != null;
+        TikaConfig config = new TikaConfig(configFileUrl);
+        Tika tika = new Tika(config);
+        Metadata md = new Metadata();
+        tika.parse(configFileUrl.openStream(), md);
+
+        for (Map.Entry<String, String> entry : expcted.entrySet()) {
+            Assert.assertEquals("mismatch for " + entry.getKey(), 
entry.getValue(), md.get(entry.getKey()));
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/test/java/org/apache/tika/utils/AnnotationUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/tika-core/src/test/java/org/apache/tika/utils/AnnotationUtilsTest.java 
b/tika-core/src/test/java/org/apache/tika/utils/AnnotationUtilsTest.java
new file mode 100644
index 0000000..eaa3549
--- /dev/null
+++ b/tika-core/src/test/java/org/apache/tika/utils/AnnotationUtilsTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.tika.utils;
+
+import aQute.bnd.annotation.metatype.Configurable;
+import org.apache.tika.config.Field;
+import org.apache.tika.config.Param;
+import org.apache.tika.exception.TikaConfigException;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * @since 6/1/16
+ */
+public class AnnotationUtilsTest {
+
+    @Test
+    public void testMisMatchType() {
+
+        class MyParser extends Configurable {
+            @Field(required = true) int config;
+        }
+
+        Map<String, Param<?>> params = new HashMap<>();
+        try {
+            params.put("config", new Param<>("config", 1));
+
+            MyParser bean = new MyParser();
+            AnnotationUtils.assignFieldParams(bean, params);
+            Assert.assertEquals(bean.config, 1);
+        } catch (TikaConfigException e) {
+            e.printStackTrace();
+            Assert.fail("Exception Not expected");
+        }
+
+        params.clear();
+        try {
+            params.put("config", new Param<>("config", "a string value"));
+            AnnotationUtils.assignFieldParams(new MyParser(), params);
+            Assert.fail("Exception expected");
+        } catch (TikaConfigException e) {
+            //expected
+        }
+    }
+
+    @Test
+    public void testPrimitiveAndBoxedTypes() {
+
+        class MyParser extends Configurable {
+            @Field(required = true) int config;
+            @Field(required = true, name = "config") Integer config2;
+        }
+
+        Map<String, Param<?>> params = new HashMap<>();
+        try {
+            MyParser bean = new MyParser();
+            int val = 100;
+            params.put("config", new Param<>("config", val));
+            AnnotationUtils.assignFieldParams(bean, params);
+            Assert.assertTrue(bean.config == bean.config2);
+            Assert.assertTrue(bean.config == val);
+        } catch (TikaConfigException e) {
+            e.printStackTrace();
+            Assert.fail("Exception Not expected");
+        }
+
+    }
+
+    @Test
+    public void testRequiredParam() {
+
+        class MyParser extends Configurable {
+            @Field(required = true) String config;
+        }
+
+        Map<String, Param<?>> params = new HashMap<>();
+        String someval = "someval";
+        params.put("config", new Param<>("config", someval));
+        try {
+            MyParser bean = new MyParser();
+            AnnotationUtils.assignFieldParams(bean, params);
+            Assert.assertEquals(bean.config, someval);
+        } catch (TikaConfigException e) {
+            e.printStackTrace();
+            Assert.fail("Exception Not expected");
+        }
+
+        params.clear();
+        try {
+            AnnotationUtils.assignFieldParams(new MyParser(), params);
+            Assert.fail("Exception expected");
+        } catch (TikaConfigException e) {
+            //expected
+        }
+    }
+
+
+    @Test
+    public void testParserInheritance() {
+
+        class Parent {
+            @Field(required = true) int overridden;
+            @Field(required = true) int parentField;
+
+        }
+
+        class Child extends Parent {
+            @Field(required = true) int overridden;
+            @Field(required = true) int childField;
+        }
+
+        int val = 1;
+        Map<String, Param<?>> params = new HashMap<>();
+        params.put("overridden", new Param<>("oevrriden", val));
+        params.put("parentField", new Param<>("parentField", val));
+        params.put("childField", new Param<>("childField", val));
+
+        try {
+            Child child = new Child();
+            AnnotationUtils.assignFieldParams(child, params);
+            Assert.assertEquals(child.overridden, val);
+            Assert.assertEquals(child.parentField, val);
+            Assert.assertEquals(child.childField, val);
+        } catch (TikaConfigException e) {
+            e.printStackTrace();
+            Assert.fail("Exception Not expected");
+        }
+
+        try {
+            params.remove("parentField");
+            AnnotationUtils.assignFieldParams(new Child(), params);
+            Assert.fail("Exception expected, parent class field not set");
+        } catch (TikaConfigException e) {
+            //expected
+        }
+    }
+
+
+
+    @Test
+    public void testParamValueInheritance() {
+
+        class Bean {
+            @Field(required = true) CharSequence field;
+        }
+
+        Bean parser = new Bean();
+        Map<String, Param<?>> params = new HashMap<>();
+        try {
+            String val = "someval";
+            params.put("field", new Param<String>("field", String.class, val));
+            AnnotationUtils.assignFieldParams(parser, params);
+            Assert.assertEquals(val, parser.field);
+        } catch (Exception e){
+            e.printStackTrace();
+            Assert.fail("Exception not expected, string is assignable to 
CharSequence");
+        }
+
+        try {
+            Date val = new Date();
+            params.put("field", new Param<Date>("field", Date.class, val));
+            AnnotationUtils.assignFieldParams(parser, params);
+            Assert.fail("Exception expected, Date is not assignable to 
CharSequence.");
+        } catch (TikaConfigException e){
+            //expected
+
+        }
+
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tika/blob/aad23d9e/tika-core/src/test/resources/org/apache/tika/config/TIKA-1986-parametrized.xml
----------------------------------------------------------------------
diff --git 
a/tika-core/src/test/resources/org/apache/tika/config/TIKA-1986-parametrized.xml
 
b/tika-core/src/test/resources/org/apache/tika/config/TIKA-1986-parametrized.xml
new file mode 100644
index 0000000..6689a19
--- /dev/null
+++ 
b/tika-core/src/test/resources/org/apache/tika/config/TIKA-1986-parametrized.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<properties>
+    <parsers>
+        <parser class="org.apache.tika.parser.DummyParametrizedParser">
+            <params>
+                <param name="testparam" type="string">testparamval</param>
+                <param name="xshort" type="short">1000</param>
+                <param name="xint" type="int">999999999</param>
+                <param name="xlong" type="long">9999999999999</param>
+                <param name="xbigint" 
type="bigint">99999999999999999999999999999999999999999999999</param>
+                <param name="xfloat" type="float">10.2</param>
+                <param name="xbool" type="bool">true</param>
+                <param name="xdouble" type="double">4.6</param>
+                <param name="xurl" type="url">http://apache.org</param>
+                <param name="xfile" type="file">/</param>
+                <param name="xuri" 
type="uri">tika://customuri?param=value</param>
+            </params>
+        </parser>
+
+    </parsers>
+</properties>

Reply via email to