Useful Gadgets: Kotlin Code Snippets

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,
Insert image description here
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.

Guess you like

Origin blog.csdn.net/Apple_wolf/article/details/123826283