Skip to content

Instantly share code, notes, and snippets.

@vincentdaniel
Created January 24, 2018 16:34
Show Gist options
  • Save vincentdaniel/cb630b03c39084f9ac7a367f922cf342 to your computer and use it in GitHub Desktop.
Save vincentdaniel/cb630b03c39084f9ac7a367f922cf342 to your computer and use it in GitHub Desktop.
From a file with multiple json messages to one data class
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import java.io.File
object Main {
/**
* - Reads a file that contains multiple json messages:
* ```
* {"id":12345,"some_key1":"value1"}
* {"id":12346,"some_key1":"value2","some_optional_key2":"value3"}
* ...
* ```
* - Generates the corresponding data class:
* ```
* data class MyClass(
* val id: Int? = null,
* val someKey1: String? = null,
* val someOptionalKey2: String? = null
* )
* ```
*/
@JvmStatic
fun main(args: Array<String>) {
val jsonLines = readFile("sample-data.log")
println(jsonLines.toDataClass("MyClass"))
}
private fun readFile(file: String): List<String> {
val inputStream = File(file).inputStream()
val lineList = mutableListOf<String>()
inputStream.bufferedReader().useLines { lines -> lines.forEach { lineList.add(it)} }
return lineList
}
private fun List<String>.toDataClass(name: String): String = this.extractSchema().toDataClass(name)
private fun List<String>.extractSchema(): Map<String, String> {
val objectMapper = ObjectMapper()
val schema = mutableMapOf<String, String>()
this.forEach { schema.updateWith(it.parseSchema(objectMapper)) }
return schema
}
private fun MutableMap<String, String>.updateWith(other: Map<String, String>) {
other.forEach { key, value ->
this.compute(key, { _, oldValue ->
when (oldValue) {
null -> value
"null" -> value
else -> oldValue
}
})
}
}
private fun Map<String, String>.toDataClass(name: String): String {
val lineSeparator = System.getProperty("line.separator") ?: "\n"
val types = this.map { (key, javaType) ->
val kotlinType = when (javaType) {
"class java.lang.Integer" -> "Int"
"class java.lang.Boolean" -> "Boolean"
else -> "String"
}
"val $key: $kotlinType? = null"
}.joinToString(",$lineSeparator")
return "data class $name($types)"
}
private fun String.parseSchema(objectMapper: ObjectMapper): Map<String, String> {
val jsonMap: Map<String, Any?> = objectMapper.readValue(this, object : TypeReference<Map<String, Any?>>() {})
return jsonMap.map { (key, value) ->
Pair(key.toCamelCase(), value?.javaClass.toString())
}.toMap().toSortedMap()
}
private fun String.toCamelCase(): String = this.split('_').joinToString("") { it.capitalize() }.decapitalize()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment