@JsonProperty annotations in your code are all put on private fields within your data class and by default Jackson doesn't scan private fields for annotations. You have to instruct it to do otherwise by putting @JsonAutoDetect annotation:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
data class CurrencyInfo(
@JsonProperty("currency_info") var currencyInfo: CurrencyInfoItem?
)
or alternatively you can move your annotations on accessor methods:
data class CurrencyInfo(
@get:JsonProperty("currency_info") var currencyInfo: CurrencyInfoItem?
)
You can do something like this:
data class CurrencyInfo @JsonCreator constructor (
@param:JsonProperty("currency_info")
@get:JsonProperty("currency_info")
val currencyInfo: CurrencyInfoItem?
)
code above translates to java as:
public final class CurrencyInfo {
@Nullable
private final String currencyInfo;
@JsonProperty("currency_info")
@Nullable
public final String getCurrencyInfo() {
return this.currencyInfo;
}
@JsonCreator
public CurrencyInfo(@JsonProperty("currency_info") @Nullable String currencyInfo) {
this.currencyInfo = currencyInfo;
}
}
code from accepted answer translates to java as following:
First (is not pure immutable):
@JsonAutoDetect(
fieldVisibility = Visibility.ANY
)
public final class CurrencyInfo {
@Nullable
private String currencyInfo;
@Nullable
public final String getCurrencyInfo() {
return this.currencyInfo;
}
public final void setCurrencyInfo(@Nullable String var1) {
this.currencyInfo = var1;
}
public CurrencyInfo(@JsonProperty("currency_info") @Nullable String currencyInfo) {
this.currencyInfo = currencyInfo;
}
}
Second (probably has problems with deserialization):
public final class CurrencyInfo {
@Nullable
private final String currencyInfo;
@JsonProperty("currency_info")
@Nullable
public final String getCurrencyInfo() {
return this.currencyInfo;
}
public CurrencyInfo(@Nullable String currencyInfo) {
this.currencyInfo = currencyInfo;
}
}
If you haven't gotten it to work with KotlinModule, since the problem you're having is that Jackson requires a default empty constructor and you currently don't have one. You could just change your MessageObject as follows and it should work:
data class MessageObject(
var id: String = "",
var name: String = "",
var otherId: String = ""
)
I created this repo with a fully functional kotlin lambda template using the Serverless Framework. Have a look for some other tidbits you might need: https://github.com/crafton/sls-aws-lambda-kotlin-gradlekt
You cannot use data class with provided RequestHandler<I, O> unfortunately, because you need register the kotlin module for your jackson mapper in order to work with data classes. But you can write you own RequestHandler, which will like this one.
Here's the code:
interface MyRequestStreamHandler<I : Any, O : Any?> : RequestStreamHandler {
val inputType: Class<I>
fun handleRequest(input: I, context: Context): O?
override fun handleRequest(inputStream: InputStream, outputStream: OutputStream, context: Context) {
handleRequest(inputStream.readJson(inputType), context).writeJsonNullable(outputStream)
}
interface MessageObjectRequestHandler : MyRequestStreamHandler< MessageObject, Output> {
override val inputType: Class<MessageObject >
get() = MessageObject::class.java
}
}
And jackson util:
private val objectMapper = jacksonObjectMapper()
.configure(JsonParser.Feature.ALLOW_COMMENTS, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerKotlinModule()
private val writer: ObjectWriter = objectMapper.writer()
fun <T : Any> readJson(clazz: Class<T>, stream: InputStream): T =
objectMapper.readValue(stream, clazz)
fun <T : Any> InputStream.readJson(clazz: Class<T>): T =
readJson(clazz, this)
fun Any?.writeJsonNullable(outputStream: OutputStream) {
if (this != null) writer.writeValue(outputStream, this)
}
Now, you can keep your MessageObject class to be data class, and your handler will look something like:
class LambdaMain : MessageObjectRequestHandler {
override fun handleRequest(input: MessageObject, context: Context): Output {
//...
}
}
You can try to add @JsonbCreator annotation to the request model classes. So in this case JSON-B will try to use the constructor to create your objects instead of the no-args / reflection
For example:
data class MyRequest @JsonbCreator constructor(
@JsonbProperty("propertyOne") val propertyOne: String,
@JsonbProperty("propertyTwo") val propertyTwo: : String
)
According to the documentation, you have to register an implementation of the (quarkus-specific) interface ObjectMapperCustomizer.
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import io.quarkus.jackson.ObjectMapperCustomizer
import javax.inject.Singleton
@Singleton
class AddKotlinModuleCustomizer : ObjectMapperCustomizer {
override fun customize(objectMapper: ObjectMapper) {
objectMapper.registerModule(KotlinModule())
}
}
And of course add the kotlin module as dependency in the pom
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<version>2.10.2</version>
</dependency>