Amazon Lambda 上 Amazon Echo/Alexa 的正确 Java handleRequest() 方法签名?
Proper Java handleRequest() method signature for Amazon Echo/Alexa on Amazon Lambda?
我正在尝试创建 Amazon Lambda function implemented in Java to work with Amazon Echo/Alexa。我使用 Eclipse Mars 作为 IDE.
这是我的 LambdaFunctionHandler
,它将接收来自 Alexa 的请求,如下所示:
public class LambdaFunctionHandler implements RequestHandler<SpeechletRequestEnvelope, SpeechletResponse> {
@Override
public SpeechletResponse handleRequest(SpeechletRequestEnvelope input, Context context) {
context.getLogger().log("Input: " + input);
// TODO: implement your handler
return null;
}
}
但是,当尝试使用来自 Alexa 的示例 JSON 输入进行测试时,我在 Eclipse 中收到错误消息:
{"errorMessage":"An error occurred during JSON parsing","errorType":"java.lang.RuntimeException","stackTrace":[],"cause":{"errorMessage":"Lcom/fasterxml/jackson/databind/ObjectMapper;","errorType":"java.lang.NoClassDefFoundError","stackTrace":["java.lang.Class.getDeclaredFields0(Native
Method)","java.lang.Class.privateGetDeclaredFields(Class.java:2583)","java.lang.Class.getDeclaredFields(Class.java:1916)","com.fasterxml.jackson.databind.introspect.AnnotatedClass._findFields(AnnotatedClass.java:689)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.resolveFields(AnnotatedClass.java:470)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.fields(AnnotatedClass.java:282)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:390)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:243)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:197)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:110)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:15)","com.fasterxml.jackson.databind.DeserializationConfig.introspect(DeserializationConfig.java:703)","com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:330)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:265)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:245)","com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)","com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:439)","com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:1588)","com.fasterxml.jackson.databind.ObjectReader.(ObjectReader.java:185)","com.fasterxml.jackson.databind.ObjectMapper._newReader(ObjectMapper.java:558)","com.fasterxml.jackson.databind.ObjectMapper.reader(ObjectMapper.java:3098)"],"cause":{"errorMessage":"com.fasterxml.jackson.databind.ObjectMapper","errorType":"java.lang.ClassNotFoundException","stackTrace":["java.net.URLClassLoader.findClass(URLClassLoader.java:381)","java.lang.ClassLoader.loadClass(ClassLoader.java:424)","java.lang.ClassLoader.loadClass(ClassLoader.java:357)","java.lang.Class.getDeclaredFields0(Native
Method)","java.lang.Class.privateGetDeclaredFields(Class.java:2583)","java.lang.Class.getDeclaredFields(Class.java:1916)","com.fasterxml.jackson.databind.introspect.AnnotatedClass._findFields(AnnotatedClass.java:689)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.resolveFields(AnnotatedClass.java:470)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.fields(AnnotatedClass.java:282)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:390)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:243)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:197)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:110)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:15)","com.fasterxml.jackson.databind.DeserializationConfig.introspect(DeserializationConfig.java:703)","com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:330)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:265)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:245)","com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)","com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:439)","com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:1588)","com.fasterxml.jackson.databind.ObjectReader.(ObjectReader.java:185)","com.fasterxml.jackson.databind.ObjectMapper._newReader(ObjectMapper.java:558)","com.fasterxml.jackson.databind.ObjectMapper.reader(ObjectMapper.java:3098)"]}}}
这是我的 JSON 输入(取自 TestColors example 在线):
{
"session": {
"new": false,
"sessionId": "session1234",
"attributes": {},
"user": {
"userId": null
},
"application": {
"applicationId": "amzn1.echo-sdk-ams.app.[unique-value-here]"
}
},
"version": "1.0",
"request": {
"intent": {
"slots": {
"Color": {
"name": "Color",
"value": "red"
}
},
"name": "MyColorIsIntent"
},
"type": "IntentRequest",
"requestId": "request5678"
}
}
所以,显然亚马逊 SpeechletRequestEnvelope
不是 handleRequest()
的正确输入 class。
handleRequest()
从 Alexa 接收请求的正确方法签名是什么?
我找不到适用于 Alexa/Echo 的 Amazon Lambda Java 示例。
我扩展了 jo.echo.lambda.utils.SpeechletLambda (https://github.com/jjaquinta/EchoProofOfConcepts/blob/master/jo.echo.lambda/jo/echo/lambda/utils/SpeechletLambda.java),这对我有用:
@Override
public void handleRequest(InputStream inputStream,
OutputStream outputStream, Context context) throws IOException
{
super.handleRequest(inputStream, outputStream, context);
}
希望对您有所帮助
这是一个完整的工作示例:
public class LambdaFunctionHandler implements RequestStreamHandler {
@Override
public void handleRequest(InputStream inputStream, OutputStream output, Context context) throws IOException {
byte serializedSpeechletRequest[] = IOUtils.toByteArray(inputStream);
SpeechletRequestEnvelope requestEnvelope = SpeechletRequestEnvelope.fromJson(serializedSpeechletRequest);
SpeechletRequest speechletRequest = requestEnvelope.getRequest();
if (speechletRequest instanceof IntentRequest) {
IntentRequest ir = (IntentRequest) speechletRequest;
String outString = "IntentRequest name: " + ir.getIntent().getName();
context.getLogger().log(outString);
output.write(outString.getBytes());
}
}
}
请注意,此 class 实现 RequestStreamHandler
,而不是 RequestHandler
。
使用问题中的输入 JSON,output.write(outString.getBytes())
将输出到 Eclipse AWS Lambda 控制台:
==================== FUNCTION OUTPUT ====================
IntentRequest name: MyColorIsIntent
...而 context.getLogger().log(outString);
导致同一行在线写入 Amazon Lambda 控制台。
您还需要确保您的项目中有一个文件夹 /lib
,并且需要包含以下 JAR:
- commons-codec-1.6.jar
- commons-lang3-3.x.jar
- jackson-annotations-2.3.2.jar
- jackson-core-2.3.2.jar
- jackson-databind-2.3.2.jar
- JakartaCommons-IO-2.4.jar
- joda-time-2.3.jar
- log4j.1.2.17.jar
- servlet-api-3.0.jar
- slf4j-api-1.7.4.jar
- slf4j-log4j12-1.7.4.jar
- alexa-skills-kit-1.0.jar
这些 JAR 可以从 Maven Central, or from the "third-party" subfolder in the AlexaSkillsKit.zip 下载。
在 Eclipse 中,您需要刷新项目以便它在 /lib
目录中看到 JAR 文件(只需按 F5),然后将 JAR 添加到 Java 构建路径:
- 在 Eclipse 中右键单击 Lambda 项目的根目录
- 点击“属性”
- Select "Java 构建路径"
- Select“库”选项卡
- 单击“添加 JAR”
- 浏览到“库”
- Select“lib”文件夹中的所有 JAR,然后单击“确定”,直到返回主 Eclipse 屏幕
感谢@jephers 提供了关于 Github 的精彩教程,我从中拼凑了很多内容:
https://github.com/jjaquinta/EchoProofOfConcepts/tree/master/jo.echo.lambda
我正在尝试创建 Amazon Lambda function implemented in Java to work with Amazon Echo/Alexa。我使用 Eclipse Mars 作为 IDE.
这是我的 LambdaFunctionHandler
,它将接收来自 Alexa 的请求,如下所示:
public class LambdaFunctionHandler implements RequestHandler<SpeechletRequestEnvelope, SpeechletResponse> {
@Override
public SpeechletResponse handleRequest(SpeechletRequestEnvelope input, Context context) {
context.getLogger().log("Input: " + input);
// TODO: implement your handler
return null;
}
}
但是,当尝试使用来自 Alexa 的示例 JSON 输入进行测试时,我在 Eclipse 中收到错误消息:
{"errorMessage":"An error occurred during JSON parsing","errorType":"java.lang.RuntimeException","stackTrace":[],"cause":{"errorMessage":"Lcom/fasterxml/jackson/databind/ObjectMapper;","errorType":"java.lang.NoClassDefFoundError","stackTrace":["java.lang.Class.getDeclaredFields0(Native Method)","java.lang.Class.privateGetDeclaredFields(Class.java:2583)","java.lang.Class.getDeclaredFields(Class.java:1916)","com.fasterxml.jackson.databind.introspect.AnnotatedClass._findFields(AnnotatedClass.java:689)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.resolveFields(AnnotatedClass.java:470)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.fields(AnnotatedClass.java:282)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:390)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:243)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:197)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:110)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:15)","com.fasterxml.jackson.databind.DeserializationConfig.introspect(DeserializationConfig.java:703)","com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:330)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:265)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:245)","com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)","com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:439)","com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:1588)","com.fasterxml.jackson.databind.ObjectReader.(ObjectReader.java:185)","com.fasterxml.jackson.databind.ObjectMapper._newReader(ObjectMapper.java:558)","com.fasterxml.jackson.databind.ObjectMapper.reader(ObjectMapper.java:3098)"],"cause":{"errorMessage":"com.fasterxml.jackson.databind.ObjectMapper","errorType":"java.lang.ClassNotFoundException","stackTrace":["java.net.URLClassLoader.findClass(URLClassLoader.java:381)","java.lang.ClassLoader.loadClass(ClassLoader.java:424)","java.lang.ClassLoader.loadClass(ClassLoader.java:357)","java.lang.Class.getDeclaredFields0(Native Method)","java.lang.Class.privateGetDeclaredFields(Class.java:2583)","java.lang.Class.getDeclaredFields(Class.java:1916)","com.fasterxml.jackson.databind.introspect.AnnotatedClass._findFields(AnnotatedClass.java:689)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.resolveFields(AnnotatedClass.java:470)","com.fasterxml.jackson.databind.introspect.AnnotatedClass.fields(AnnotatedClass.java:282)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addFields(POJOPropertiesCollector.java:390)","com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collect(POJOPropertiesCollector.java:243)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.collectProperties(BasicClassIntrospector.java:197)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:110)","com.fasterxml.jackson.databind.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:15)","com.fasterxml.jackson.databind.DeserializationConfig.introspect(DeserializationConfig.java:703)","com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:330)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:265)","com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:245)","com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:143)","com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:439)","com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:1588)","com.fasterxml.jackson.databind.ObjectReader.(ObjectReader.java:185)","com.fasterxml.jackson.databind.ObjectMapper._newReader(ObjectMapper.java:558)","com.fasterxml.jackson.databind.ObjectMapper.reader(ObjectMapper.java:3098)"]}}}
这是我的 JSON 输入(取自 TestColors example 在线):
{
"session": {
"new": false,
"sessionId": "session1234",
"attributes": {},
"user": {
"userId": null
},
"application": {
"applicationId": "amzn1.echo-sdk-ams.app.[unique-value-here]"
}
},
"version": "1.0",
"request": {
"intent": {
"slots": {
"Color": {
"name": "Color",
"value": "red"
}
},
"name": "MyColorIsIntent"
},
"type": "IntentRequest",
"requestId": "request5678"
}
}
所以,显然亚马逊 SpeechletRequestEnvelope
不是 handleRequest()
的正确输入 class。
handleRequest()
从 Alexa 接收请求的正确方法签名是什么?
我找不到适用于 Alexa/Echo 的 Amazon Lambda Java 示例。
我扩展了 jo.echo.lambda.utils.SpeechletLambda (https://github.com/jjaquinta/EchoProofOfConcepts/blob/master/jo.echo.lambda/jo/echo/lambda/utils/SpeechletLambda.java),这对我有用:
@Override
public void handleRequest(InputStream inputStream,
OutputStream outputStream, Context context) throws IOException
{
super.handleRequest(inputStream, outputStream, context);
}
希望对您有所帮助
这是一个完整的工作示例:
public class LambdaFunctionHandler implements RequestStreamHandler {
@Override
public void handleRequest(InputStream inputStream, OutputStream output, Context context) throws IOException {
byte serializedSpeechletRequest[] = IOUtils.toByteArray(inputStream);
SpeechletRequestEnvelope requestEnvelope = SpeechletRequestEnvelope.fromJson(serializedSpeechletRequest);
SpeechletRequest speechletRequest = requestEnvelope.getRequest();
if (speechletRequest instanceof IntentRequest) {
IntentRequest ir = (IntentRequest) speechletRequest;
String outString = "IntentRequest name: " + ir.getIntent().getName();
context.getLogger().log(outString);
output.write(outString.getBytes());
}
}
}
请注意,此 class 实现 RequestStreamHandler
,而不是 RequestHandler
。
使用问题中的输入 JSON,output.write(outString.getBytes())
将输出到 Eclipse AWS Lambda 控制台:
==================== FUNCTION OUTPUT ====================
IntentRequest name: MyColorIsIntent
...而 context.getLogger().log(outString);
导致同一行在线写入 Amazon Lambda 控制台。
您还需要确保您的项目中有一个文件夹 /lib
,并且需要包含以下 JAR:
- commons-codec-1.6.jar
- commons-lang3-3.x.jar
- jackson-annotations-2.3.2.jar
- jackson-core-2.3.2.jar
- jackson-databind-2.3.2.jar
- JakartaCommons-IO-2.4.jar
- joda-time-2.3.jar
- log4j.1.2.17.jar
- servlet-api-3.0.jar
- slf4j-api-1.7.4.jar
- slf4j-log4j12-1.7.4.jar
- alexa-skills-kit-1.0.jar
这些 JAR 可以从 Maven Central, or from the "third-party" subfolder in the AlexaSkillsKit.zip 下载。
在 Eclipse 中,您需要刷新项目以便它在 /lib
目录中看到 JAR 文件(只需按 F5),然后将 JAR 添加到 Java 构建路径:
- 在 Eclipse 中右键单击 Lambda 项目的根目录
- 点击“属性”
- Select "Java 构建路径"
- Select“库”选项卡
- 单击“添加 JAR”
- 浏览到“库”
- Select“lib”文件夹中的所有 JAR,然后单击“确定”,直到返回主 Eclipse 屏幕
感谢@jephers 提供了关于 Github 的精彩教程,我从中拼凑了很多内容:
https://github.com/jjaquinta/EchoProofOfConcepts/tree/master/jo.echo.lambda