The version of deliverable. Example value can be 1.0-SNAPSHOT.
*/ - @Parameter(property = "version", defaultValue = "${version}", required = true) + @Parameter(property = "version", defaultValue = "${version}") public String version; @Parameter(property = "alias") @@ -354,7 +365,7 @@ private void initFileName() { } private void initVersion() { - version = version.replace(".", "-"); + if (version != null) { version = version.replace(".", "-"); } } @SuppressWarnings("rawtypes") @@ -387,19 +398,20 @@ private void initLambdaFunctionsConfiguration() throws MojoExecutionException, I validate(lambdaFunctions); lambdaFunctions = lambdaFunctions.stream().map(lambdaFunction -> { + initFromAnnotations(lambdaFunction); + String functionName = ofNullable(lambdaFunction.getFunctionName()).orElseThrow(() -> new IllegalArgumentException("Configuration error. LambdaFunction -> 'functionName' is required")); lambdaFunction.withFunctionName(addSuffix(functionName)) - .withHandler(ofNullable(lambdaFunction.getHandler()).orElseThrow(() -> new IllegalArgumentException("Configuration error. LambdaFunction -> 'handler' is required"))) .withDescription(ofNullable(lambdaFunction.getDescription()).orElse("")) .withTimeout(ofNullable(lambdaFunction.getTimeout()).orElse(timeout)) .withMemorySize(ofNullable(lambdaFunction.getMemorySize()).orElse(memorySize)) .withSubnetIds(ofNullable(vpcSubnetIds).orElse(new ArrayList<>())) .withSecurityGroupsIds(ofNullable(vpcSecurityGroupIds).orElse(new ArrayList<>())) - .withVersion(version) .withPublish(ofNullable(lambdaFunction.isPublish()).orElse(publish)) .withLambdaRoleArn(ofNullable(lambdaFunction.getLambdaRoleArn()).orElse(lambdaRoleArn)) .withAliases(aliases(lambdaFunction.isPublish())) + .withEnvironmentVariables(environmentVariables(lambdaFunction)) .withTriggers(ofNullable(lambdaFunction.getTriggers()).map(triggers -> triggers.stream() .map(trigger -> { trigger.withRuleName(addSuffix(trigger.getRuleName())); @@ -410,12 +422,33 @@ private void initLambdaFunctionsConfiguration() throws MojoExecutionException, I return trigger; }) .collect(toList())) - .orElse(new ArrayList<>())) - .withEnvironmentVariables(environmentVariables(lambdaFunction)); - + .orElse(Collections.emptyList())); + + if (lambdaFunction.getVersion() == null) { + lambdaFunction.setVersion(ofNullable(version).orElseThrow(() -> new IllegalArgumentException("Configuration error. Version is required if handlers don't self-identify their version via annotations."))); + } + return lambdaFunction; }).collect(toList()); } + + private void initFromAnnotations(LambdaFunction lf) { + String handler = ofNullable(lf.getHandler()).orElseThrow(() -> new IllegalArgumentException("Configuration error. LambdaFunction -> 'handler' is required")); + try { + Class> c = Class.forName(handler); + Object obj = c.newInstance(); + if (obj instanceof IsDocumented) { + Documentation d = ((IsDocumented) obj).getDocumentation(); + if (lf.getFunctionName() == null && d.getName() != null) { lf.setFunctionName(d.getName().toString()); } + if (lf.getDescription() == null && d.getDescription() != null) { lf.setDescription(d.getDescription().toString()); } + if (lf.getVersion() == null && d.getVersion() != null) { lf.setVersion(d.getVersion().toString()); } + } + } catch (ClassNotFoundException e) { + getLog().warn("Handler class " + handler + " not on classpath and can't be introspected for function metadata annotations. If you would like to specify function metadata via annotations, ensure that this project is in the plugin's dependencies."); + } catch (InstantiationException | IllegalAccessException e) { + getLog().warn("Handler class " + handler + " can't be instantiated for function metadata annotations. If you would like to specify function metadata via annotations, ensure your handler has a no-arg constructor."); + } + } @SuppressWarnings("unchecked") private Map