I'm trying to create an Amazon Lambda function implemented in Java to work with Amazon Echo/Alexa. I'm using Eclipse Mars as the IDE.
Here's what my LambdaFunctionHandler, which will receive the requests from Alexa, looks like:
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;
}
}
However, when trying to test this with sample JSON input from Alexa, I get the error in 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)"]}}}
Here's my JSON input (taken from the TestColors example online):
{
"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"
}
}
So, apparently Amazon SpeechletRequestEnvelope isn't the correct input class for handleRequest().
What is the correct method signature for handleRequest() to receive requests from Alexa?
I can't find a Java example for Amazon Lambda that works with Alexa/Echo.
Here's a full working example:
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());
}
}
}
Note that this class implements RequestStreamHandler, NOT RequestHandler.
Using the input JSON from the question, the output.write(outString.getBytes()) will result in the output to the Eclipse AWS Lambda console:
==================== FUNCTION OUTPUT ====================
IntentRequest name: MyColorIsIntent
...while context.getLogger().log(outString); results in the same line being written to the Amazon Lambda console online.
You also need to make sure you have a folder /lib in your project, and the following JARs need to be included:
These JARs can be downloaded from Maven Central, or from the "third-party" subfolder in the AlexaSkillsKit.zip.
In Eclipse, you need to refresh the project so it sees the JAR files in the /lib directory (just hit F5), and then add the JARs to the Java build path:
Thanks to @jephers for the pointer to this great tutorial on Github where I pieced a lot of this together from:
https://github.com/jjaquinta/EchoProofOfConcepts/tree/master/jo.echo.lambda
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With