diff --git a/azure-functions-maven-plugin/pom.xml b/azure-functions-maven-plugin/pom.xml
index 373a6e4cd5..497f4f684f 100644
--- a/azure-functions-maven-plugin/pom.xml
+++ b/azure-functions-maven-plugin/pom.xml
@@ -6,7 +6,7 @@
com.microsoft.azure
azure-functions-maven-plugin
- 0.1.8-SNAPSHOT
+ 0.1.9-SNAPSHOT
maven-plugin
Maven Plugin for Azure Functions
Maven Plugin for Azure Functions
diff --git a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AddMojo.java b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AddMojo.java
index 2ab8d0c96a..d6e940e59b 100644
--- a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AddMojo.java
+++ b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AddMojo.java
@@ -47,6 +47,7 @@ public class AddMojo extends AbstractFunctionMojo {
public static final String SAVE_FILE = "Step 4 of 4: Saving function to file";
public static final String SAVE_FILE_DONE = "Successfully saved new function at ";
public static final String FILE_EXIST = "Function already exists at %s. Please specify a different function name.";
+ private static final String FUNCTION_NAME_REGEXP = "^[a-zA-Z][a-zA-Z\\d_\\-]*$";
//region Properties
@@ -92,6 +93,10 @@ public String getFunctionName() {
return functionName;
}
+ public String getClassName() {
+ return getFunctionName().replace('-', '_');
+ }
+
public String getFunctionTemplate() {
return functionTemplate;
}
@@ -219,6 +224,7 @@ protected Map prepareRequiredParameters(final FunctionTemplate t
final Map params = new HashMap<>();
params.put("functionName", getFunctionName());
+ params.put("className", getClassName());
params.put("packageName", getFunctionPackageName());
prepareTemplateParameters(template, params);
@@ -233,14 +239,14 @@ protected void prepareFunctionName() throws MojoFailureException {
if (settings != null && !settings.isInteractiveMode()) {
assureInputInBatchMode(getFunctionName(),
- str -> isNotEmpty(str) && isIdentifier(str) && !isKeyword(str),
+ str -> isNotEmpty(str) && str.matches(FUNCTION_NAME_REGEXP),
this::setFunctionName,
true);
} else {
assureInputFromUser("Enter value for Function Name: ",
getFunctionName(),
- str -> isNotEmpty(str) && isIdentifier(str) && !isKeyword(str),
- "Input should be a valid Java class name.",
+ str -> isNotEmpty(str) && str.matches(FUNCTION_NAME_REGEXP),
+ "Function name must start with a letter and can contain letters, digits, '_' and '-'",
this::setFunctionName);
}
}
@@ -333,7 +339,7 @@ protected File getPackageDir() {
}
protected File getTargetFile(final File packageDir) throws Exception {
- final String functionName = getFunctionName() + ".java";
+ final String functionName = getClassName() + ".java";
final File targetFile = new File(packageDir, functionName);
if (targetFile.exists()) {
throw new FileAlreadyExistsException(format(FILE_EXIST, targetFile.getAbsolutePath()));
diff --git a/azure-functions-maven-plugin/src/main/resources/templates.json b/azure-functions-maven-plugin/src/main/resources/templates.json
index 83e9c32bb0..84a5bbcc36 100644
--- a/azure-functions-maven-plugin/src/main/resources/templates.json
+++ b/azure-functions-maven-plugin/src/main/resources/templates.json
@@ -9,7 +9,7 @@
"userPrompt": []
},
"files": {
- "function.java": "package $packageName$;\n\nimport java.util.*;\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with HTTP trigger.\n */\npublic class $functionName$ {\n /**\n * This function will listen at HTTP endpoint \"/api/$functionName$\". Two approaches to invoke it using \"curl\" command in bash:\n * 1. curl -d \"Http Body\" {your host}/api/$functionName$\n * 2. curl {your host}/api/$functionName$?name=HTTP%20Query\n */\n @FunctionName(\"$functionName$\")\n public HttpResponseMessage httpHandler(\n @HttpTrigger(name = \"req\", methods = { \"get\", \"post\" }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java HTTP trigger processed a request.\");\n\n // Parse query parameters\n String query = request.getQueryParameters().get(\"name\");\n String name = request.getBody().orElse(query);\n\n if (name == null) {\n return request.createResponse(400, \"Please pass a name on the query string or in the request body\");\n } else {\n return request.createResponse(200, \"Hello, \" + name);\n }\n }\n}\n"
+ "function.java": "package $packageName$;\n\nimport java.util.*;\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with HTTP trigger.\n */\npublic class $className$ {\n /**\n * This function will listen at HTTP endpoint \"/api/$functionName$\". Two approaches to invoke it using \"curl\" command in bash:\n * 1. curl -d \"Http Body\" {your host}/api/$functionName$\n * 2. curl {your host}/api/$functionName$?name=HTTP%20Query\n */\n @FunctionName(\"$functionName$\")\n public HttpResponseMessage httpHandler(\n @HttpTrigger(name = \"req\", methods = { \"get\", \"post\" }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java HTTP trigger processed a request.\");\n\n // Parse query parameters\n String query = request.getQueryParameters().get(\"name\");\n String name = request.getBody().orElse(query);\n\n if (name == null) {\n return request.createResponse(400, \"Please pass a name on the query string or in the request body\");\n } else {\n return request.createResponse(200, \"Hello, \" + name);\n }\n }\n}\n"
}
},
{
@@ -25,7 +25,7 @@
]
},
"files": {
- "function.java": "package $packageName$;\n\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with Azure Blob trigger.\n */\npublic class $functionName$ {\n /**\n * This function will be invoked when a new or updated blob is detected at the specified path. The blob contents are provided as input to this function.\n */\n @FunctionName(\"$functionName$\")\n @StorageAccount(\"$connection$\")\n public void blobHandler(\n @BlobTrigger(name = \"content\", path = \"$path$\", dataType = \"binary\") byte[] content,\n @BindingName(\"name\") String name,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java Blob trigger function processed a blob. Name: \" + name + \"\\n Size: \" + content.length + \" Bytes\");\n }\n}\n"
+ "function.java": "package $packageName$;\n\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with Azure Blob trigger.\n */\npublic class $className$ {\n /**\n * This function will be invoked when a new or updated blob is detected at the specified path. The blob contents are provided as input to this function.\n */\n @FunctionName(\"$functionName$\")\n @StorageAccount(\"$connection$\")\n public void blobHandler(\n @BlobTrigger(name = \"content\", path = \"$path$\", dataType = \"binary\") byte[] content,\n @BindingName(\"name\") String name,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java Blob trigger function processed a blob. Name: \" + name + \"\\n Size: \" + content.length + \" Bytes\");\n }\n}\n"
}
},
{
@@ -41,7 +41,7 @@
]
},
"files": {
- "function.java": "package $packageName$;\n\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with Azure Storage Queue trigger.\n */\npublic class $functionName$ {\n /**\n * This function will be invoked when a new message is received at the specified path. The message contents are provided as input to this function.\n */\n @FunctionName(\"$functionName$\")\n public void queueHandler(\n @QueueTrigger(name = \"message\", queueName = \"$queueName$\", connection = \"$connection$\") String message,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java Queue trigger function processed a message: \" + message);\n }\n}\n"
+ "function.java": "package $packageName$;\n\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with Azure Storage Queue trigger.\n */\npublic class $className$ {\n /**\n * This function will be invoked when a new message is received at the specified path. The message contents are provided as input to this function.\n */\n @FunctionName(\"$functionName$\")\n public void queueHandler(\n @QueueTrigger(name = \"message\", queueName = \"$queueName$\", connection = \"$connection$\") String message,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java Queue trigger function processed a message: \" + message);\n }\n}\n"
}
},
{
@@ -56,7 +56,7 @@
]
},
"files": {
- "function.java": "package $packageName$;\n\nimport java.time.*;\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with Timer trigger.\n */\npublic class $functionName$ {\n /**\n * This function will be invoked periodically according to the specified schedule.\n */\n @FunctionName(\"$functionName$\")\n public void timerHandler(\n @TimerTrigger(name = \"timerInfo\", schedule = \"$schedule$\") String timerInfo,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java Timer trigger function executed at: \" + LocalDateTime.now());\n }\n}\n"
+ "function.java": "package $packageName$;\n\nimport java.time.*;\nimport com.microsoft.azure.serverless.functions.annotation.*;\nimport com.microsoft.azure.serverless.functions.*;\n\n/**\n * Azure Functions with Timer trigger.\n */\npublic class $className$ {\n /**\n * This function will be invoked periodically according to the specified schedule.\n */\n @FunctionName(\"$functionName$\")\n public void timerHandler(\n @TimerTrigger(name = \"timerInfo\", schedule = \"$schedule$\") String timerInfo,\n final ExecutionContext context\n ) {\n context.getLogger().info(\"Java Timer trigger function executed at: \" + LocalDateTime.now());\n }\n}\n"
}
}
]
diff --git a/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/AddMojoTest.java b/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/AddMojoTest.java
index 726a78ccb6..5e7abb9c29 100644
--- a/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/AddMojoTest.java
+++ b/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/AddMojoTest.java
@@ -53,6 +53,36 @@ public void doExecute() throws Exception {
assertTrue(newFunctionFile.exists());
}
+ @Test(expected = MojoFailureException.class)
+ public void doExecuteWithInvalidFunctionName() throws Exception {
+ final AddMojo mojo = getMojoFromPom();
+ final Settings settings = new Settings();
+ settings.setInteractiveMode(false);
+ ReflectionUtils.setVariableValueInObject(mojo, "basedir", new File("target/test"));
+ ReflectionUtils.setVariableValueInObject(mojo, "settings", settings);
+ mojo.setFunctionTemplate("HttpTrigger");
+ mojo.setFunctionName("$NewFunction");
+ mojo.setFunctionPackageName("com.microsoft.azure");
+
+ mojo.doExecute();
+ }
+
+ @Test
+ public void doExecuteWithSpecialFunctionName() throws Exception {
+ final AddMojo mojo = getMojoFromPom();
+ ReflectionUtils.setVariableValueInObject(mojo, "basedir", new File("target/test"));
+ mojo.setFunctionTemplate("HttpTrigger");
+ mojo.setFunctionName("New-Function");
+ mojo.setFunctionPackageName("com.microsoft.azure");
+
+ final File newFunctionFile = new File("target/test/src/main/java/com/microsoft/azure/New_Function.java");
+ newFunctionFile.delete();
+
+ mojo.doExecute();
+
+ assertTrue(newFunctionFile.exists());
+ }
+
@Test
public void assureInputFromUser() throws Exception {
final AddMojo mojo = getMojoFromPom();