Article directory
1. Convert any object into Map
inline fun <reified T : Any> T.asMap() : Map<String, Any?> {
val props = T::class.memberProperties.associateBy {
it.name }
return props.keys.associateWith {
props[it]?.get(this) }
}
2. Use ObjectMapper to convert objects
2.1 Convert object to JsonString
data class Person(val name: String, var age: Int)
fun obj2JsonString(obj: Person){
val objectMapper = ObjectMapper().registerModule(JavaTimeModule()).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
return objectMapper.writeValueAsString(person)
}
2.2 JsonString to object
data class Person(val name: String = " ", var age: Int = 23)
fun getPersonFromJsonString(): Person {
val objectMapper = ObjectMapper().registerModule(JavaTimeModule()).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
val jsonString = "{\"name\":\"tom\",\"age\":34}"
return objectMapper.readValue(jsonString, Person::class.java)
}
Note:
You can see that each field of the data class here has a default value. If not, an error will be reported:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.Person` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"name":"tom","age":34}"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1615)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1077)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1332)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:331)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:164)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4524)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3466)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434)
This is because a parameterless constructor is missing, and the data class does not generate a parameterless constructor. A default value needs to be added for each parameter to generate a parameterless constructor. On the Kotlin official website,
default values are added to each attribute of each data class. What an annoying thing! Do you want to write about each one? I don’t want to anyway.
Fortunately, Kotlin officially has a solution:
use the no-arg compilation plug-in and make the following configuration in the pom file:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<!-- Or "jpa" for JPA support -->
<plugin>no-arg</plugin>
</compilerPlugins>
<pluginOptions>
<option>no-arg:annotation=com.my.Annotation</option>
<!-- Call instance initializers in the synthetic constructor -->
<!-- <option>no-arg:invokeInitializers=true</option> -->
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
2.3 JsonString contains list
If the json string contains a list, it should be written as:
data class Person(val name: String = " ", var age: Int = 23)
fun getPersonFromJsonString(): List<*> {
val objectMapper = ObjectMapper().registerModule(JavaTimeModule()).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
val jsonString = "[{\"name\":\"tom\",\"age\":34},{\"name\":\"tom\",\"age\":34}]"
return objectMapper.readValue(jsonString, List::class.java)}
However, in the list obtained in this way, the elements in the list are not recognized, but are stored in the list in the form of linkedHashMap. If I want to take out a specific object type, it should be like this:
data class Person(val name: String = " ", var age: Int = 23)
fun getPersonFromJsonString(): List<*> {
val objectMapper = ObjectMapper().registerModule(JavaTimeModule()).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
val jsonString = "[{\"name\":\"tom\",\"age\":34},{\"name\":\"tom\",\"age\":34}]"
var people: List<Person> = objectMapper.readValue(jsonString, objectMapper.typeFactory.constructCollectionType(List::class.java, Person::class.java))
return people
In this way, you can get the specific instances contained in the list.