Added support in API component framework for specifying nullableOptions

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

Branch: refs/heads/linkedin-component
Commit: 91e19c10da4fde3ab23ad87b602399740facafe6
Parents: bd7d94d
Author: Dhiraj Bokde <dhira...@yahoo.com>
Authored: Thu Jul 10 14:25:38 2014 -0700
Committer: Dhiraj Bokde <dhira...@yahoo.com>
Committed: Thu Jul 10 14:25:38 2014 -0700

----------------------------------------------------------------------
 .../util/component/AbstractApiProducer.java     | 23 +++--
 .../camel/util/component/ApiConsumerHelper.java |  2 +-
 .../camel/util/component/ApiMethodHelper.java   | 90 ++++++++++++++++++--
 .../camel/util/component/ApiMethodParser.java   |  4 +-
 .../util/component/ApiMethodHelperTest.java     | 21 +++--
 components/camel-box/pom.xml                    |  4 +
 .../component/box/AbstractBoxTestSupport.java   |  1 -
 ...BoxCollaborationsManagerIntegrationTest.java |  2 +-
 .../box/IBoxCommentsManagerIntegrationTest.java |  4 +-
 .../box/IBoxEventsManagerIntegrationTest.java   |  2 +-
 .../box/IBoxFilesManagerIntegrationTest.java    | 13 ++-
 .../box/IBoxFoldersManagerIntegrationTest.java  |  4 +-
 .../box/IBoxGroupsManagerIntegrationTest.java   | 10 +--
 .../box/IBoxSearchManagerIntegrationTest.java   |  2 +-
 .../IBoxSharedItemsManagerIntegrationTest.java  |  2 +-
 .../box/IBoxUsersManagerIntegrationTest.java    |  6 +-
 .../src/main/java/__name__Endpoint.java         |  2 +-
 .../src/it/all-it/pom.xml                       |  3 +
 .../maven/AbstractApiMethodGeneratorMojo.java   | 10 +--
 .../camel/maven/ApiComponentGeneratorMojo.java  | 29 +++++++
 .../java/org/apache/camel/maven/ApiProxy.java   | 10 +++
 .../camel/maven/DocumentGeneratorMojo.java      |  9 +-
 .../maven/JavadocApiMethodGeneratorMojo.java    | 15 ++--
 .../src/main/resources/api-collection.vm        |  6 +-
 .../src/main/resources/api-document.vm          | 22 ++++-
 .../src/main/resources/api-route-test.vm        |  2 +-
 .../maven/ApiComponentGeneratorMojoTest.java    |  1 +
 27 files changed, 234 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
 
b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
index 17276aa..b4c7427 100644
--- 
a/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
+++ 
b/camel-core/src/main/java/org/apache/camel/util/component/AbstractApiProducer.java
@@ -145,7 +145,7 @@ public abstract class AbstractApiProducer<E extends Enum<E> 
& ApiName, T>
 
             // filter candidates based on endpoint and exchange properties
             final Set<String> argNames = properties.keySet();
-            final List<ApiMethod> filteredMethods = 
ApiMethodHelper.filterMethods(candidates,
+            final List<ApiMethod> filteredMethods = 
methodHelper.filterMethods(candidates,
                     ApiMethodHelper.MatchType.SUPER_SET,
                     argNames.toArray(new String[argNames.size()]));
 
@@ -172,15 +172,24 @@ public abstract class AbstractApiProducer<E extends 
Enum<E> & ApiName, T>
         if (inBodyProperty != null) {
 
             Object value = exchange.getIn().getBody();
-            try {
-                value = 
endpoint.getCamelContext().getTypeConverter().mandatoryConvertTo(
+            if (value != null) {
+                try {
+                    value = 
endpoint.getCamelContext().getTypeConverter().mandatoryConvertTo(
                         
endpoint.getConfiguration().getClass().getDeclaredField(inBodyProperty).getType(),
                         exchange, value);
-            } catch (Exception e) {
-                exchange.setException(new RuntimeCamelException(String.format(
-                        "Error converting value %s to property %s: %s", value, 
inBodyProperty, e.getMessage()), e));
+                } catch (Exception e) {
+                    exchange.setException(new 
RuntimeCamelException(String.format(
+                            "Error converting value %s to property %s: %s", 
value, inBodyProperty, e.getMessage()), e));
 
-                return false;
+                    return false;
+                }
+            } else {
+                // allow null values for inBody only if its a nullable option
+                if 
(!methodHelper.getNullableArguments().contains(inBodyProperty)) {
+                    exchange.setException(new 
NullPointerException(inBodyProperty));
+
+                    return false;
+                }
             }
 
             log.debug("Property [{}] has message body value {}", 
inBodyProperty, value);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
 
b/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
index 779dea0..30a7745 100644
--- 
a/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
+++ 
b/camel-core/src/main/java/org/apache/camel/util/component/ApiConsumerHelper.java
@@ -55,7 +55,7 @@ public final class ApiConsumerHelper {
         propertyNamesInterceptor.interceptPropertyNames(argNames);
 
         final String[] argNamesArray = argNames.toArray(new 
String[argNames.size()]);
-        List<ApiMethod> filteredMethods = ApiMethodHelper.filterMethods(
+        List<ApiMethod> filteredMethods = endpoint.methodHelper.filterMethods(
                 endpoint.getCandidates(), ApiMethodHelper.MatchType.SUPER_SET, 
argNamesArray);
 
         if (filteredMethods.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java 
b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
index b4401eb..7ec732b 100644
--- 
a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
+++ 
b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodHelper.java
@@ -52,19 +52,27 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
 
     // maps aliases to actual method names
     private final HashMap<String, Set<String>> aliasesMap = new 
HashMap<String, Set<String>>();
+    private final List<String> nullableArguments;
 
     /**
      * Create a helper to work with a {@link ApiMethod}, using optional method 
aliases.
      * @param apiMethodEnum {@link ApiMethod} enumeration class
      * @param aliases Aliases mapped to actual method names
+     * @param nullableArguments names of arguments that default to null value
      */
-    public ApiMethodHelper(Class<T> apiMethodEnum, Map<String, String> 
aliases) {
+    public ApiMethodHelper(Class<T> apiMethodEnum, Map<String, String> 
aliases, List<String> nullableArguments) {
 
         // validate ApiMethod Enum
         if (apiMethodEnum == null) {
             throw new IllegalArgumentException("ApiMethod enumeration cannot 
be null");
         }
 
+        if (nullableArguments != null && !nullableArguments.isEmpty()) {
+            this.nullableArguments = Collections.unmodifiableList(new 
ArrayList<String>(nullableArguments));
+        } else {
+            this.nullableArguments = Collections.emptyList();
+        }
+
         final Map<Pattern, String> aliasPatterns = new HashMap<Pattern, 
String>();
         for (Map.Entry<String, String> alias : aliases.entrySet()) {
             if (alias.getKey() == null || alias.getValue() == null) {
@@ -144,6 +152,53 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
 
         }
 
+        // validate nullableArguments
+        if (!validArguments.keySet().containsAll(this.nullableArguments)) {
+            List<String> unknowns = new 
ArrayList<String>(this.nullableArguments);
+            unknowns.removeAll(validArguments.keySet());
+            throw new IllegalArgumentException("Unknown nullable arguments " + 
unknowns.toString());
+        }
+
+        // validate aliases
+        for (Map.Entry<String, Set<String>> entry : aliasesMap.entrySet()) {
+
+            // look for aliases that match multiple methods
+            final Set<String> methodNames = entry.getValue();
+            if (methodNames.size() > 1) {
+
+                // get mapped methods
+                final List<T> aliasedMethods = new ArrayList<T>();
+                for (String methodName : methodNames) {
+                    List<T> mappedMethods = methodMap.get(methodName);
+                    aliasedMethods.addAll(mappedMethods);
+                }
+
+                // look for argument overlap
+                for (T method : aliasedMethods) {
+                    final List<String> argNames = new 
ArrayList<String>(method.getArgNames());
+                    argNames.removeAll(this.nullableArguments);
+
+                    final Set<T> ambiguousMethods = new HashSet<T>();
+                    for (T otherMethod : aliasedMethods) {
+                        if (method != otherMethod) {
+                            final List<String> otherArgsNames = new 
ArrayList<String>(otherMethod.getArgNames());
+                            otherArgsNames.removeAll(this.nullableArguments);
+
+                            if (argNames.equals(otherArgsNames)) {
+                                ambiguousMethods.add(method);
+                                ambiguousMethods.add(otherMethod);
+                            }
+                        }
+                    }
+
+                    if (!ambiguousMethods.isEmpty()) {
+                        throw new IllegalArgumentException(
+                            String.format("Ambiguous alias %s for methods %s", 
entry.getKey(), ambiguousMethods));
+                    }
+                }
+            }
+        }
+
         LOG.debug("Found {} unique method names in {} methods", 
methodMap.size(), methods.length);
     }
 
@@ -192,12 +247,23 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
      * @return methods with arguments that satisfy the match type.<p/>
      * For SUPER_SET match, if methods with exact match are found, methods 
that take a subset are ignored
      */
-    public static List<ApiMethod> filterMethods(List<? extends ApiMethod> 
methods, MatchType matchType,
+    public List<ApiMethod> filterMethods(List<? extends ApiMethod> methods, 
MatchType matchType,
                                                           String... argNames) {
-        List<String> argsList = Arrays.asList(argNames);
+        // original arguments
+        final List<String> argsList = Arrays.asList(argNames);
+        // supplied arguments with missing nullable arguments
+        final List<String> withNullableArgsList;
+        if (!nullableArguments.isEmpty()) {
+            withNullableArgsList = new ArrayList<String>(argsList);
+            withNullableArgsList.addAll(nullableArguments);
+        } else {
+            withNullableArgsList = null;
+        }
+
         // list of methods that have all args in the given names
         final List<ApiMethod> result = new ArrayList<ApiMethod>();
         final List<ApiMethod> extraArgs = new ArrayList<ApiMethod>();
+        final List<ApiMethod> nullArgs = new ArrayList<ApiMethod>();
 
         for (ApiMethod method : methods) {
             final List<String> methodArgs = method.getArgNames();
@@ -225,12 +291,18 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
                         // method takes a subset, unused args
                         extraArgs.add(method);
                     }
+                } else if (result.isEmpty() && extraArgs.isEmpty()) {
+                    // avoid looking for nullable args by checking for empty 
result and extraArgs
+                    if (withNullableArgsList != null && 
withNullableArgsList.containsAll(methodArgs)) {
+                        nullArgs.add(method);
+                    }
                 }
                 break;
             }
         }
 
-        return Collections.unmodifiableList(result.isEmpty() ? extraArgs : 
result);
+        // preference order is exact match, matches with extra args, matches 
with null args
+        return Collections.unmodifiableList(result.isEmpty() ? 
(extraArgs.isEmpty() ? nullArgs : extraArgs) : result);
     }
 
     /**
@@ -283,7 +355,7 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
     }
 
     /**
-     * Get argument types and names used by all methods.
+     * Returns argument types and names used by all methods.
      * @return map with argument names as keys, and types as values
      */
     public Map<String, Class<?>> allArguments() {
@@ -291,6 +363,14 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
     }
 
     /**
+     * Returns argument names that can be set to null if not specified.
+     * @return list of argument names
+     */
+    public List<String> getNullableArguments() {
+        return nullableArguments;
+    }
+
+    /**
      * Get the type for the given argument name.
      * @param argName argument name
      * @return argument type

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java 
b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
index 92f5750..27c8be8 100644
--- 
a/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
+++ 
b/camel-core/src/main/java/org/apache/camel/util/component/ApiMethodParser.java
@@ -126,7 +126,9 @@ public abstract class ApiMethodParser<T> {
                 final Class<?> type = forName(argsMatcher.group(1));
                 argTypes.add(type);
 
-                final String typeArgs = argsMatcher.group(2) != null ? 
argsMatcher.group(2).replaceAll(" ", "") : null;
+                final String typeArgsGroup = argsMatcher.group(2);
+                final String typeArgs = typeArgsGroup != null
+                    ? typeArgsGroup.substring(1, typeArgsGroup.length() - 
1).replaceAll(" ", "") : null;
                 arguments.add(new Argument(argsMatcher.group(3), type, 
typeArgs));
             }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
 
b/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
index 4e2fee7..5f55794 100644
--- 
a/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/util/component/ApiMethodHelperTest.java
@@ -24,11 +24,10 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
-import org.junit.Test;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import org.junit.Test;
 
 public class ApiMethodHelperTest {
 
@@ -38,7 +37,7 @@ public class ApiMethodHelperTest {
     static {
         final HashMap<String, String> aliases = new HashMap<String, String>();
         aliases.put("say(.*)", "$1");
-        apiMethodHelper = new ApiMethodHelper<TestMethod>(TestMethod.class, 
aliases);
+        apiMethodHelper = new ApiMethodHelper<TestMethod>(TestMethod.class, 
aliases, Arrays.asList("names"));
     }
 
     @Test
@@ -64,23 +63,29 @@ public class ApiMethodHelperTest {
 
     @Test
     public void testFilterMethods() {
-        List<ApiMethod> methods = 
ApiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.EXACT);
+        List<ApiMethod> methods = 
apiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.EXACT);
         assertEquals("Exact match failed for sayHi()", 1, methods.size());
         assertEquals("Exact match failed for sayHi()", TestMethod.SAYHI, 
methods.get(0));
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.SUBSET);
+        methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.SUBSET);
         assertEquals("Subset match failed for sayHi(*)", 2, methods.size());
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.SUBSET, "name");
+        methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.SUBSET, "name");
         assertEquals("Subset match failed for sayHi(name)", 1, methods.size());
         assertEquals("Exact match failed for sayHi()", TestMethod.SAYHI_1, 
methods.get(0));
 
-        methods = ApiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.SUPER_SET, "name");
+        methods = apiMethodHelper.filterMethods(Arrays.asList(sayHis), 
ApiMethodHelper.MatchType.SUPER_SET, "name");
         assertEquals("Super set match failed for sayHi(name)", 1, 
methods.size());
         assertEquals("Exact match failed for sayHi()", TestMethod.SAYHI_1, 
methods.get(0));
 
-        methods = 
ApiMethodHelper.filterMethods(Arrays.asList(TestMethod.values()), 
ApiMethodHelper.MatchType.SUPER_SET, "name");
+        methods = 
apiMethodHelper.filterMethods(Arrays.asList(TestMethod.values()), 
ApiMethodHelper.MatchType.SUPER_SET, "name");
         assertEquals("Super set match failed for sayHi(name)", 2, 
methods.size());
+
+        // test nullable names
+        methods = apiMethodHelper.filterMethods(
+            Arrays.asList(TestMethod.GREETALL, TestMethod.GREETALL_1, 
TestMethod.GREETALL_2),
+            ApiMethodHelper.MatchType.SUPER_SET);
+        assertEquals("Super set match with null args failed for 
greetAll(names)", 1, methods.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-box/pom.xml b/components/camel-box/pom.xml
index aee2b38..307d8a6 100644
--- a/components/camel-box/pom.xml
+++ b/components/camel-box/pom.xml
@@ -315,6 +315,7 @@
                   
<proxyClass>org.apache.camel.component.box.internal.LongPollingEventsManager</proxyClass>
                   
<fromSignatureFile>${project.basedir}/src/signatures/long-polling-events-manager.txt</fromSignatureFile>
                   <excludeConfigNames>callback</excludeConfigNames>
+                  <nullableOptions/>
                 </api>
                 <api>
                   <apiName>search</apiName>
@@ -390,6 +391,9 @@
               <fromJavadoc>
                 
<excludeClasses>BoxResourceManager|BoxItemsManager</excludeClasses>
               </fromJavadoc>
+              <nullableOptions>
+                <nullableOption>defaultRequest</nullableOption>
+              </nullableOptions>
               <aliases>
                 <alias>
                   <methodPattern>[gs]et(.+)</methodPattern>

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
index 130bcaf..177c4e2 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/AbstractBoxTestSupport.java
@@ -48,7 +48,6 @@ public abstract class AbstractBoxTestSupport extends 
CamelTestSupport {
     private static final String LINE_SEPARATOR = 
System.getProperty("line.separator");
     private static final String TEST_OPTIONS_PROPERTIES = 
"/test-options.properties";
     private static final String REFRESH_TOKEN_PROPERTY = "refreshToken";
-    protected static final BoxDefaultRequestObject BOX_DEFAULT_REQUEST_OBJECT 
= new BoxDefaultRequestObject();
     protected static final BoxPagingRequestObject BOX_PAGING_REQUEST_OBJECT = 
BoxPagingRequestObject.pagingRequestObject(100, 0);
     protected static String testUserId;
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
index eea80af..0931481 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCollaborationsManagerIntegrationTest.java
@@ -68,7 +68,7 @@ public class IBoxCollaborationsManagerIntegrationTest extends 
AbstractBoxTestSup
         // parameter type is String
         headers.put("CamelBox.collabId", collabId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
         requestBodyAndHeaders("direct://DELETECOLLABORATION", null, headers);
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
index 178852a..eec01ce 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxCommentsManagerIntegrationTest.java
@@ -73,7 +73,7 @@ public class IBoxCommentsManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.commentId", commentId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
         requestBodyAndHeaders("direct://DELETECOMMENT", null, headers);
     }
 
@@ -85,7 +85,7 @@ public class IBoxCommentsManagerIntegrationTest extends 
AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.commentId", comment.getId());
             // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
             BoxComment result = requestBodyAndHeaders("direct://GETCOMMENT", 
null, headers);
 
             LOG.debug("getComment: " + result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
index b86ed4b..b771d67 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxEventsManagerIntegrationTest.java
@@ -42,7 +42,7 @@ public class IBoxEventsManagerIntegrationTest extends 
AbstractBoxTestSupport {
     @Test
     public void testGetEventOptions() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject 
message body for single parameter "defaultRequest"
-        BoxCollection result = requestBody("direct://GETEVENTOPTIONS", 
BOX_DEFAULT_REQUEST_OBJECT);
+        BoxCollection result = requestBody("direct://GETEVENTOPTIONS", null);
 
         assertNotNull("getEventOptions result", result);
         LOG.debug("getEventOptions: " + result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
index 5fd8239..00ac056 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFilesManagerIntegrationTest.java
@@ -114,7 +114,7 @@ public class IBoxFilesManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
         InputStream result = requestBodyAndHeaders("direct://DOWNLOADFILE", 
null, headers);
 
         assertNotNull("downloadFile result", result);
@@ -134,7 +134,7 @@ public class IBoxFilesManagerIntegrationTest extends 
AbstractBoxTestSupport {
         final FileTransferListener fileTransferListener = new 
FileTransferListener();
         headers.put("CamelBox.listener", fileTransferListener);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DOWNLOADFILE_1", null, headers);
 
@@ -164,7 +164,7 @@ public class IBoxFilesManagerIntegrationTest extends 
AbstractBoxTestSupport {
         final FileTransferListener fileTransferListener = new 
FileTransferListener();
         headers.put("CamelBox.listener", fileTransferListener);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DOWNLOADFILE_2", null, headers);
 
@@ -195,9 +195,8 @@ public class IBoxFilesManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
-//        BoxFile result = requestBodyAndHeaders("direct://GETFILE", null, 
headers);
         BoxFile result = requestBodyAndHeaders("direct://GETFILE", null, 
headers);
 
         assertNotNull("getFile result", result);
@@ -210,7 +209,7 @@ public class IBoxFilesManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         com.box.boxjavalibv2.dao.BoxCollection result = 
requestBodyAndHeaders("direct://GETFILECOMMENTS", null, headers);
 
@@ -224,7 +223,7 @@ public class IBoxFilesManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.fileId", testFileId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         java.util.List result = 
requestBodyAndHeaders("direct://GETFILEVERSIONS", null, headers);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
index fc46361..3fb018b 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxFoldersManagerIntegrationTest.java
@@ -128,7 +128,7 @@ public class IBoxFoldersManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.folderId", "0");
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         final BoxFolder result = (BoxFolder) 
requestBodyAndHeaders("direct://GETFOLDER", null, headers);
         assertNotNull("getFolder result", result);
@@ -145,7 +145,7 @@ public class IBoxFoldersManagerIntegrationTest extends 
AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.folderId", testFolder.getId());
             // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             List result = 
requestBodyAndHeaders("direct://GETFOLDERCOLLABORATIONS", null, headers);
             assertNotNull("getFolderCollaborations result", result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
index 14e8ad4..7207e50 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxGroupsManagerIntegrationTest.java
@@ -103,7 +103,7 @@ public class IBoxGroupsManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.groupId", groupId);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DELETEGROUP", null, headers);
     }
@@ -119,7 +119,7 @@ public class IBoxGroupsManagerIntegrationTest extends 
AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.membershipId", membership.getId());
             // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
             requestBodyAndHeaders("direct://DELETEMEMBERSHIP", null, headers);
         } finally {
             deleteGroup(group.getId());
@@ -134,7 +134,7 @@ public class IBoxGroupsManagerIntegrationTest extends 
AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.groupId", group.getId());
             // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             BoxCollection result = 
requestBodyAndHeaders("direct://GETALLCOLLABORATIONS", null, headers);
 
@@ -148,7 +148,7 @@ public class IBoxGroupsManagerIntegrationTest extends 
AbstractBoxTestSupport {
     @Test
     public void testGetAllGroups() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject 
message body for single parameter "defaultRequest"
-        BoxCollection result = requestBody("direct://GETALLGROUPS", 
BOX_DEFAULT_REQUEST_OBJECT);
+        BoxCollection result = requestBody("direct://GETALLGROUPS", null);
 
         assertNotNull("getAllGroups result", result);
         LOG.debug("getAllGroups: " + result);
@@ -165,7 +165,7 @@ public class IBoxGroupsManagerIntegrationTest extends 
AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.membershipId", membership.getId());
             // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             BoxGroupMembership result = 
requestBodyAndHeaders("direct://GETMEMBERSHIP", null, headers);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
index 8648787..5423076 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSearchManagerIntegrationTest.java
@@ -45,7 +45,7 @@ public class IBoxSearchManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.searchQuery", "Test");
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         com.box.boxjavalibv2.dao.BoxCollection result = 
requestBodyAndHeaders("direct://SEARCH", null, headers);
         assertNotNull("search result", result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
index a9e0443..5017953 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxSharedItemsManagerIntegrationTest.java
@@ -35,7 +35,7 @@ public class IBoxSharedItemsManagerIntegrationTest extends 
AbstractBoxTestSuppor
     @Test
     public void testGetSharedItem() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject 
message body for single parameter "defaultRequest"
-        BoxItem result = requestBody("direct://GETSHAREDITEM", 
BOX_DEFAULT_REQUEST_OBJECT);
+        BoxItem result = requestBody("direct://GETSHAREDITEM", null);
 
         assertNotNull("getSharedItem result", result);
         LOG.debug("getSharedItem: " + result);

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
index a2f473c..11a77db 100644
--- 
a/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
+++ 
b/components/camel-box/src/test/java/org/apache/camel/component/box/IBoxUsersManagerIntegrationTest.java
@@ -89,7 +89,7 @@ public class IBoxUsersManagerIntegrationTest extends 
AbstractBoxTestSupport {
         // parameter type is String
         headers.put("CamelBox.emailId", CAMEL_EMAIL_ALIAS);
         // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-        headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//        headers.put("CamelBox.defaultRequest", null);
 
         requestBodyAndHeaders("direct://DELETEEMAILALIAS", null, headers);
     }
@@ -125,7 +125,7 @@ public class IBoxUsersManagerIntegrationTest extends 
AbstractBoxTestSupport {
     @Test
     public void testGetCurrentUser() throws Exception {
         // using com.box.restclientv2.requestsbase.BoxDefaultRequestObject 
message body for single parameter "defaultRequest"
-        BoxUser result = requestBody("direct://GETCURRENTUSER", 
BOX_DEFAULT_REQUEST_OBJECT);
+        BoxUser result = requestBody("direct://GETCURRENTUSER", null);
 
         assertNotNull("getCurrentUser result", result);
         LOG.debug("getCurrentUser: " + result);
@@ -140,7 +140,7 @@ public class IBoxUsersManagerIntegrationTest extends 
AbstractBoxTestSupport {
             // parameter type is String
             headers.put("CamelBox.userId", enterpriseUser.getId());
             // parameter type is 
com.box.restclientv2.requestsbase.BoxDefaultRequestObject
-            headers.put("CamelBox.defaultRequest", BOX_DEFAULT_REQUEST_OBJECT);
+//            headers.put("CamelBox.defaultRequest", null);
 
             List result = requestBodyAndHeaders("direct://GETEMAILALIASES", 
null, headers);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
----------------------------------------------------------------------
diff --git 
a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
 
b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
index e7a0340..a804e7b 100644
--- 
a/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
+++ 
b/tooling/archetypes/camel-archetype-api-component/src/main/resources/archetype-resources/__artifactId__-component/src/main/java/__name__Endpoint.java
@@ -75,7 +75,7 @@ public class ${name}Endpoint extends 
AbstractApiEndpoint<${name}ApiName, ${name}
     @Override
     protected void afterConfigureProperties() {
         // TODO create API proxy, set connection properties, etc.
-        switch ((${name}ApiName) apiName) {
+        switch (apiName) {
             case HELLO_FILE:
                 apiProxy = new ${name}FileHello();
                 break;

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml 
b/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
index 369f65b..d1d6449 100644
--- a/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
+++ b/tooling/maven/camel-api-component-maven-plugin/src/it/all-it/pom.xml
@@ -151,6 +151,9 @@
                       <name>extraString</name>
                     </extraOption>
                   </extraOptions>
+                  <nullableOptions>
+                    <nullableOption>namesList</nullableOption>
+                  </nullableOptions>
                   
<fromSignatureFile>../../../src/test/resources/test-proxy-signatures.txt</fromSignatureFile>
                 </api>
                 <api>

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
index 6ddb5b6..387fc7c 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/AbstractApiMethodGeneratorMojo.java
@@ -309,8 +309,10 @@ public abstract class AbstractApiMethodGeneratorMojo 
extends AbstractApiMethodBa
             parameterizedType.append('<');
 
             // Note: its ok to split, since we don't support parsing nested 
type arguments
-            String[] argTypes = typeArgs.split(",");
+            final String[] argTypes = typeArgs.split(",");
             boolean ignore = false;
+            final int nTypes = argTypes.length;
+            int i = 0;
             for (String argType : argTypes) {
 
                 // try loading as is first
@@ -326,7 +328,7 @@ public abstract class AbstractApiMethodGeneratorMojo 
extends AbstractApiMethodBa
                         parameterizedType.append(
                             
getCanonicalName(getProjectClassLoader().loadClass("java.lang." + argType)));
                     } catch (ClassNotFoundException e1) {
-                        log.warn("Ignoring type parameters < " + typeArgs + "> 
for argument " + argument.getName()
+                        log.warn("Ignoring type parameters <" + typeArgs + "> 
for argument " + argument.getName()
                                  + ", unable to load parametric type argument 
" + argType, e1);
                         ignore = true;
                     }
@@ -335,14 +337,12 @@ public abstract class AbstractApiMethodGeneratorMojo 
extends AbstractApiMethodBa
                 if (ignore) {
                     // give up
                     break;
-                } else {
+                } else if (++i < nTypes) {
                     parameterizedType.append(",");
                 }
             }
 
             if (!ignore) {
-                // replace the last ',' with '>'
-                parameterizedType.deleteCharAt(parameterizedType.length() - 1);
                 parameterizedType.append('>');
                 canonicalName = parameterizedType.toString();
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
index 290d322..e099c61 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiComponentGeneratorMojo.java
@@ -48,6 +48,12 @@ public class ApiComponentGeneratorMojo extends 
AbstractApiMethodBaseMojo {
     protected FromJavadoc fromJavadoc = new FromJavadoc();
 
     /**
+     * Names of options that can be set to null value if not specified.
+     */
+    @Parameter
+    private String[] nullableOptions;
+
+    /**
      * Method alias patterns for all APIs.
      */
     @Parameter
@@ -102,6 +108,11 @@ public class ApiComponentGeneratorMojo extends 
AbstractApiMethodBaseMojo {
                 if (!aliases.isEmpty() && api.getAliases().isEmpty()) {
                     api.setAliases(aliases);
                 }
+
+                // set common nullable options if needed
+                if (api.getNullableOptions() == null) {
+                    api.setNullableOptions(nullableOptions);
+                }
             }
 
             // generate ApiCollection
@@ -239,4 +250,22 @@ public class ApiComponentGeneratorMojo extends 
AbstractApiMethodBaseMojo {
         }
         return builder.toString();
     }
+
+    public static String getNullableOptionValues(String[] nullableOptions) {
+
+        if (nullableOptions == null || nullableOptions.length == 0) {
+            return "";
+        }
+
+        final StringBuilder builder = new StringBuilder();
+        final int nOptions = nullableOptions.length;
+        int i = 0;
+        for (String option : nullableOptions) {
+            builder.append('"').append(option).append('"');
+            if (++i < nOptions) {
+                builder.append(", ");
+            }
+        }
+        return builder.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
index a8b8912..5df0a7b 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/ApiProxy.java
@@ -44,6 +44,8 @@ public class ApiProxy {
 
     private ExtraOption[] extraOptions;
 
+    private String[] nullableOptions;
+
     private List<ApiMethodAlias> aliases = Collections.emptyList();
 
     public String getApiName() {
@@ -110,6 +112,14 @@ public class ApiProxy {
         this.extraOptions = extraOptions;
     }
 
+    public String[] getNullableOptions() {
+        return nullableOptions;
+    }
+
+    public void setNullableOptions(String[] nullableOptions) {
+        this.nullableOptions = nullableOptions;
+    }
+
     public List<ApiMethodAlias> getAliases() {
         return aliases;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
index cdd1e1a..ff155ca 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/DocumentGeneratorMojo.java
@@ -458,18 +458,21 @@ public class DocumentGeneratorMojo extends 
AbstractGeneratorMojo implements Mave
     private static String getCanonicalName(ParameterizedType fieldType) {
         final Type[] typeArguments = fieldType.getActualTypeArguments();
 
-        if (typeArguments.length > 0) {
+        final int nArguments = typeArguments.length;
+        if (nArguments > 0) {
             final StringBuilder result = new 
StringBuilder(getCanonicalName((Class<?>) fieldType.getRawType()));
             result.append("&lt;");
+            int i = 0;
             for (Type typeArg : typeArguments) {
                 if (typeArg instanceof ParameterizedType) {
                     result.append(getCanonicalName((ParameterizedType) 
typeArg));
                 } else {
                     result.append(getCanonicalName((Class<?>) typeArg));
                 }
-                result.append(',');
+                if (++i < nArguments) {
+                    result.append(',');
+                }
             }
-            result.deleteCharAt(result.length() - 1);
             result.append("&gt;");
             return result.toString();
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
index 7cf74d6..bf58017 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/java/org/apache/camel/maven/JavadocApiMethodGeneratorMojo.java
@@ -285,19 +285,22 @@ public class JavadocApiMethodGeneratorMojo extends 
AbstractApiMethodGeneratorMoj
             }
 
             // make sure number of types and names match
-            if (typeList.size() != argNames.size()) {
+            final int nTypes = typeList.size();
+            if (nTypes != argNames.size()) {
                 throw new IllegalArgumentException("Unexpected Javadoc error, 
different number of arg types and names");
             }
 
-            final String[] names = argNames.toArray(new 
String[argNames.size()]);
-            StringBuilder builder = new StringBuilder("(");
+            final String[] names = argNames.toArray(new String[nTypes]);
+            final StringBuilder builder = new StringBuilder("(");
             int i = 0;
             for (String type : typeList) {
                 // split on space or non-breaking space
-                builder.append(type).append(" 
").append(names[i++]).append(",");
+                builder.append(type).append(' ').append(names[i++]);
+                if (i < nTypes) {
+                    builder.append(',');
+                }
             }
-            builder.deleteCharAt(builder.length() - 1);
-            builder.append(")");
+            builder.append(')');
             return builder.toString();
         }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
index 1b73e7f..6d5b850 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-collection.vm
@@ -21,7 +21,9 @@
  */
 package $packageName;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 #set( $componentConfig = "${componentName}Configuration" )
@@ -42,6 +44,7 @@ public final class $collectionName extends 
ApiCollection<${apiNameEnum}, ${compo
 
     private ${collectionName}() {
         final Map<String, String> aliases = new HashMap<String, String>();
+        List<String> nullableArgs;
 #foreach( $api in $apis )
 
         aliases.clear();
@@ -50,7 +53,8 @@ public final class $collectionName extends 
ApiCollection<${apiNameEnum}, ${compo
 #end
 #set( $apiMethod = ${helper.getApiMethod($api.ProxyClass)} )
 #set( $apiName = "${apiNameEnum}.${helper.getEnumConstant($api.ApiName)}" )
-        apis.put($apiName, new ApiMethodHelper<$apiMethod>(${apiMethod}.class, 
aliases));
+        nullableArgs = 
Arrays.asList(${helper.getNullableOptionValues($api.NullableOptions)});
+        apis.put($apiName, new ApiMethodHelper<$apiMethod>(${apiMethod}.class, 
aliases, nullableArgs));
         apiMethods.put(${apiMethod}.class, ${apiName});
 #end
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
index 9e14962..5f65a00 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-document.vm
@@ -69,7 +69,7 @@
     <hr/>
     <p>
         The ${componentName} Component can be configured with the options 
below.
-        These options can be provided using the component's bean property 
<code>configuration</code> of type <code>$componentConfiguration.Name</code>.
+        These options can be provided using the component's bean property 
<code>configuration</code> of type <code>$componentConfig.Name</code>.
     </p>
     <table>
         <tr>
@@ -98,6 +98,7 @@
 #end
     <p>
         Endpoint options that are not mandatory are denoted by [].
+        When there are no mandatory options for an endpoint, one of the set of 
[] options MUST be provided.
         Producer endpoints can also use a special option 
<b><code>inBody</code></b> that in turn should contain
         the name of the endpoint option whose value will be contained in the 
Camel Exchange In message.
     </p>
@@ -129,6 +130,14 @@
     </table>
     <h3>URI Options</h3>
     <hr/>
+#set ( $nullableArguments = $apiHelpers.get("").NullableArguments )
+#if( !$nullableArguments.isEmpty )
+    <p>
+        If a value is not provided for one of the option(s) 
${nullableArguments.toString()}
+        either in the endpoint URI or in a message header, it will be assumed 
to be <code>null</code>.
+        Note that the <code>null</code> value(s) will only be used if other 
options do not satisfy matching endpoints.
+    </p>
+#end
     <table>
         <tr>
             <th>Name</th>
@@ -159,7 +168,8 @@
             <th>Result Body Type</th>
         </tr>
 #set( $endpointConfig = $apiConfigs.get($apiName) )
-#set( $endpoints = $helper.getEndpoints($apiMethod.Value, 
$apiHelpers.get($apiName), $endpointConfig) )
+#set( $anApiHelper = $apiHelpers.get($apiName) )
+#set( $endpoints = $helper.getEndpoints($apiMethod.Value, $anApiHelper, 
$endpointConfig) )
 #foreach( $endpoint in $endpoints )
         <tr>
             <td>$endpoint.Endpoint</td>
@@ -171,6 +181,14 @@
     </table>
     <h4>URI Options for <em>$apiName</em></h4>
     <hr/>
+#set ( $nullableArguments = $anApiHelper.NullableArguments )
+#if( !$nullableArguments.Empty )
+    <p>
+        If a value is not provided for one of the option(s) 
${nullableArguments.toString()}
+        either in the endpoint URI or in a message header, it will be assumed 
to be <code>null</code>.
+        Note that the <code>null</code> value(s) will only be used if other 
options do not satisfy matching endpoints.
+    </p>
+#end
     <table>
         <tr>
             <th>Name</th>

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
 
b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
index 5c91def..90e54f4 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/main/resources/api-route-test.vm
@@ -34,7 +34,7 @@ import ${packageName}.${componentName}ApiCollection;
 import ${packageName}.${enumName};
 
 /**
- * Test class for $proxyType.Name APIs.
+ * Test class for {@link ${proxyType.Name}} APIs.
  * TODO Move the file to src/test/java, populate parameter values, and remove 
@Ignore annotations.
  * The class source won't be generated again if the generator MOJO finds it 
under src/test/java.
  */

http://git-wip-us.apache.org/repos/asf/camel/blob/91e19c10/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
----------------------------------------------------------------------
diff --git 
a/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
 
b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
index cfb460d..52cf975 100644
--- 
a/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
+++ 
b/tooling/maven/camel-api-component-maven-plugin/src/test/java/org/apache/camel/maven/ApiComponentGeneratorMojoTest.java
@@ -52,6 +52,7 @@ public class ApiComponentGeneratorMojoTest extends 
AbstractGeneratorMojoTest {
         // exclude name2, and int times
         mojo.apis[0].setExcludeConfigNames("name2");
         mojo.apis[0].setExcludeConfigTypes("int");
+        mojo.apis[0].setNullableOptions(new String[] {"namesList"});
 
         List<ApiMethodAlias> aliases = new ArrayList<ApiMethodAlias>();
         aliases.add(new ApiMethodAlias("get(.+)", "$1"));

Reply via email to