Thank you always for your help.
I got a problem in my project.
I want to delete Zoned Id and leave only time.
How to remove zoned Id?
It is written using kotlin in Spring Boot Framework.
data class AvailableScheduleRequest (
val address: String,
val date: LocalDate,
val people: Long,
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "Asia/Seoul")
val hour: ZonedDateTime
)
#RestController
class Controller(
val newBookingElasticSearchService: NewBookingElasticSearchService
) {
#RequestMapping("/")
#ResponseBody
fun get(#RequestBody param: Map<String, Any>): List<AvailableRestaurant> {
val json = JacksonUtils.om.writeValueAsString(param)
val availableScheduleRequest =
JacksonUtils.om.readValue(json, AvailableScheduleRequest::class.java)
println(availableScheduleRequest.hour)
}
}
object JacksonUtils {
val om = ObjectMapper()
init {
val module = SimpleModule()
module.addDeserializer(String::class.java, JsonRawValueDeserializer.INSTANCE)
om.registerModule(JavaTimeModule())
om.registerModule(KotlinModule())
om.registerModule(module)
om.dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")
om.setTimeZone(TimeZone.getDefault())
om.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
om.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true)
om.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
om.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
}
This code outputs:
2019-10-02T07:00+09:00[Asia/Seoul]
But I wanna get this:
2019-10-02T07:00+09:00
How to get this?
Thank you for your efforts all the time!!
Instead of ZonedDateTime, you could use OffsetDateTime.
Related
I am trying to implement a custom deserializer and when I try to install it on the ObjectMapper it never gets invoked, but when I use it directly as an annotation on the class, it does. Can someone explain why and how I can actually install it on the object mapper itself?
This is never invoked
val bug = ObjectMapper().registerModule(KotlinModule.Builder().build())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(SimpleModule().addDeserializer(Bug::class.java, BugDeserializer()))
.readValue(bugStream, Bug::class.java)
data class Bug(
#JsonProperty("rptno")
val id: Long,
#JsonProperty("status")
#JsonDeserialize(using = StatusDeserializer::class)
val status: Status,
#JsonProperty("reported_date")
val reportedDate:Instant,
#JsonProperty("updated_date")
val updatedDate: Instant,
// val pillar: String = "",
#JsonProperty("product_id")
#JsonDeserialize(using = ProductDeserializer::class)
val product: Product,
#JsonProperty("assignee")
val assignee: String,
// val serviceRequests: List<Long> = listOf(),
#JsonProperty("subject")
val title: String,
#JsonProperty("bug_type")
val type: String
)
But, this does:
val bug = ObjectMapper().registerModule(KotlinModule.Builder().build())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.readValue(bugStream, Bug::class.java)
#JsonDeserialize(using = BugDeserializer::class)
data class Bug(
#JsonProperty("rptno")
val id: Long,
#JsonProperty("status")
#JsonDeserialize(using = StatusDeserializer::class)
val status: Status,
#JsonProperty("reported_date")
val reportedDate:Instant,
#JsonProperty("updated_date")
val updatedDate: Instant,
// val pillar: String = "",
#JsonProperty("product_id")
#JsonDeserialize(using = ProductDeserializer::class)
val product: Product,
#JsonProperty("assignee")
val assignee: String,
// val serviceRequests: List<Long> = listOf(),
#JsonProperty("subject")
val title: String,
#JsonProperty("bug_type")
val type: String
)
```kotlin
I am trying to return List<List<Map<String, String>>> from a function in kotlin. I'm new to kotlin.
Edit1
Here's how I am attempting to to this
val a = mutableListOf(mutableListOf(mutableMapOf<String, String>()))
The problem with the above variable is, I am unable to figure out how to insert data into this variable. I tried with this:
val a = mutableListOf(mutableListOf(mutableMapOf<String, String>()))
val b = mutableListOf(mutableMapOf<String, String>())
val c = mutableMapOf<String, String>()
c.put("c", "n")
b.add(c)
a.add(b)
This is giving me:
[[{}], [{}, {c=n}]]
What I want is [[{c=n}]]
Can someone tell me how I can insert data into it?
The end goal I am trying to achieve is to store data in the form of List<List<Map<String, String>>>
EDIT 2
The function for which I am trying to write this dat structure:
fun processReport(file: Scanner): MutableList<List<Map<String, String>>> {
val result = mutableListOf<List<Map<String, String>>>()
val columnNames = file.nextLine().split(",")
while (file.hasNext()) {
val record = mutableListOf<Map<String, String>>()
val rowValues = file.nextLine()
.replace(",(?=[^\"]*\"[^\"]*(?:\"[^\"]*\"[^\"]*)*$)".toRegex(), "")
.split(",")
for (i in rowValues.indices) {
record.add(mapOf(columnNames[i] to rowValues[i]))
print(columnNames[i] + " : " + rowValues[i] + " ")
}
result.add(record)
}
return result
}
You don't need to use mutable data structures. You can define it like this:
fun main() {
val a = listOf(listOf(mapOf("c" to "n")))
println(a)
}
Output:
[[{c=n}]]
If you wanted to use mutable data structures and add the data later, you could do it like this:
fun main() {
val map = mutableMapOf<String, String>()
val innerList = mutableListOf<Map<String, String>>()
val outerList = mutableListOf<List<Map<String, String>>>()
map["c"] = "n"
innerList.add(map)
outerList.add(innerList)
println(outerList)
}
The output is the same, although the lists and maps are mutable.
In response to the 2nd edit. Ah, you're parsing a CSV. You shouldn't try to do that yourself, but you should use a library. Here's an example using Apache Commons CSV
fun processReport(file: File): List<List<Map<String, String>>> {
val parser = CSVParser.parse(file, Charset.defaultCharset(), CSVFormat.DEFAULT.withHeader())
return parser.records.map {
it.toMap().entries.map { (k, v) -> mapOf(k to v) }
}
}
For the following CSV:
foo,bar,baz
a,b,c
1,2,3
It produces:
[[{foo=a}, {bar=b}, {baz=c}], [{foo=1}, {bar=2}, {baz=3}]]
Note that you can simplify it further if you're happy returning a list of maps:
fun processReport(file: File): List<Map<String, String>> {
val parser = CSVParser.parse(file, Charset.defaultCharset(), CSVFormat.DEFAULT.withHeader())
return parser.records.map { it.toMap() }
}
Output:
[{foo=a, bar=b, baz=c}, {foo=1, bar=2, baz=3}]
I'm using Charset.defaultCharset() here, but you should change it to whatever character set the CSV is in.
I am trying to integrate a Dialogflow Agent with Pepper: https://developer.softbankrobotics.com/pepper-qisdk/lessons/integrating-chatbot-dialogflow
I followed all the steps until the Testing your agent in standalone section, where I have to add the following Kotlin code to the DialogflowSource class:
import com.google.auth.oauth2.ServiceAccountCredentials
import com.google.cloud.dialogflow.v2.*
import java.io.InputStream
class DialogflowDataSource constructor(credentialsStream : InputStream) {
private val credentials : ServiceAccountCredentials
= ServiceAccountCredentials.fromStream(credentialsStream)
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
SessionsClient.create(sessionsSettings).use { sessionsClient -> //Error: Unresolved reference for .use
val session = SessionName.of(credentials.projectId, sessionId)
val textInput = TextInput.newBuilder()
.setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput
.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
return response.queryResult.fulfillmentText
}
} //Error: A 'return' expression required in a function with a block body ('{...}')
}
I'm new to Kotlin, so I don't really know how to fix this. Any help would be appreciated!
First, why would you use use? It seems you meant to call apply instead. But in fact you could just write:
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
val sessionClient = SessionsClient.create(sessionsSettings)
val session = SessionName.of(credentials.projectId, sessionId)
val textInput =
TextInput.newBuilder().setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
return response.queryResult.fulfillmentText
}
But if you care using use (or apply), the lambda you provide to it should not directly make the outer function detectIntentTexts return. Instead, let your lambda return its result locally, and let detectIntentTexts return it:
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
return SessionsClient.create(sessionsSettings).apply { sessionsClient ->
val session = SessionName.of(credentials.projectId, sessionId)
val textInput = TextInput.newBuilder()
.setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput
.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
response.queryResult.fulfillmentText
}
}
}
I have a kotlin data class described as:
data class Credentials(val p: String, val id: String, val key: String, val pass: String, val out: String)
I am trying to read from 2 text files located in a directory, and put them into this data class.
How the data looks:
config file
[user1]
out = specialk
id = mike
[user2]
out = specialk
id = mike
[user3]
out = specialk
id = mike
credentials file
[user1]
key = qwer1
pass = 3452
[user2]
key = qwer3
pass = 345232
[user3]
key = qwer5
pass = 3452gfd
Setting it up:
val homepath = System.getProperty("user.home")
val config = "$homepath/foobar"
val cred= "$homepath/credbar"
val configStream: InputStream = File(config).inputStream()
val credStream: InputStream = File(cred).inputStream()
This next part is something I am unsure of. What I think is that I should be reading each stream and putting it into a list of data class grouped by the user. However, I'm not sure how that should be accomplished.
configStream.bufferedReader().forEachLine {
// put to data class here.
}
I can't write single comment cause i am new at Stackowerflow. Sorry about that. If this file holds your app backup you can take backup as JSON file. This is much easier than this.
Firstly you need to add Gson dependency in your project
implementation 'com.google.code.gson:gson:2.8.6'
Secondly you need to two parser object that is for make parse to data class to JSON and JSON to data class.
You need to declare your export and import type as below
val exportType = object : TypeToken<List<Credentials>>() {}.type
And after that for convert your data to JSON String you can use this
private fun List<Credentials>.toJson() = Gson().toJson(this, exportType)
this code returns String.
and if you want to convert JSON to String you can use this code
private fun fromJson(str: String): List<Credentials> {
return try {
Gson().fromJson(str, exportType)
} catch (e: Exception) {
Log.e("From Json Exception", "$e")
emptyList()
}
}
this code returns list of your data class.
I hope this can help you. I did not ask is this you want to do because my Stacowerflow account is new.
Basically I would try to convert your streams into two strings
val configInputFileString = convertStreamToString(configStream)
val credentialsInputFileString = convertStreamToString(credStream)
You can easily convert a stream by using this function:
fun convertStreamToString(stream: InputStream?): String? {
val reader = BufferedReader(InputStreamReader(stream))
val sb = StringBuilder()
var line: String? = null
while (reader.readLine().also { line = it } != null) {
sb.append(line).append("\n")
}
reader.close()
return sb.toString()
}
Once you have the two streams, I would define to different data classes to get the elements of the streams:
data class UserConfig(val placeholder: String, val out: String, val id: String)
data class UserCredentials(val placeholder: String, val key: String, val pass: String)
for each stream you need to get each row, splitting by new line character \n and clearing unuseful parts:
private fun getUserConfigs(elements: List<String>): ArrayList<UserConfig> {
val configs = arrayListOf<UserConfig>()
for (element in elements) {
val splittedConfig = element
.replace("out = ", "")
.replace("id = ", "")
.split("\n")
val config = UserConfig(splittedConfig[0], splittedConfig[1], splittedConfig[2])
configs.add(config)
}
return configs
}
private fun getUserCredentials(elements: List<String>): ArrayList<UserCredentials> {
val credentials = arrayListOf<UserCredentials>()
for (element in elements) {
val splittedCredentials = element
.replace("key = ", "")
.replace("pass = ", "")
.split("\n")
val config = UserCredentials(splittedCredentials[0], splittedCredentials[1], splittedCredentials[2])
credentials.add(config)
}
return credentials
}
Now you can map userConfig and credentialConfigs in a usersMap
val userConfigs = getUserConfigs(configInputFileString!!.split("\n\n"))
val credentialConfigs = getUserCredentials(credentialsInputFileString!!.split("\n\n"))
val usersMap = userConfigs.map { userConfig ->
userConfig to credentialConfigs.find { it.placeholder == userConfig.placeholder }
}
Finally you can transform the usersMap to match your data class by doing:
val credentials = usersMap.map { Credentials(it.first.placeholder, it.first.id, it.second!!.key, it.second!!.pass, it.first.out) }
As long as your files seem to be of Windows INI format you can use third-party library Ini4J to parse them.
Parse both files and merge two Inis into list of Credentials
val configs = Ini(File(config))
val credentials = Ini(File(cred))
val result: List<Credentials> = configs.keySet().map { user ->
Credentials(p = user, // or whatever 'p' is
id = configs.get(user, "id")!!,
key = credentials.get(user, "key")!!,
pass = credentials.get(user, "pass")!!,
out = configs.get(user, "out")!!)
}
We are using kotlin dsl to as a user friendly builder to take input and generate data. Is there a way to do the opposite of that ?
ie, convert existing data into dsl ?
Can this kotlin representation be converted to dsl ?
val person = Person("John", 25)
val person = person {
name = "John"
age = 25
}
Unless you're really crazy about { and some commas, below is an absolutely valid Kotlin code:
data class Person(
val name: String,
val age: Int
)
val person = Person(
name = "John",
age = 25
)
I seems really close to what you want and comes out-of-the-box.
Of course, you can achieve the syntax you want by writing some extra code, like:
import kotlin.properties.Delegates
data class Person(
val name: String,
val age: Int
)
class PersonDSL{
lateinit var name: String
var age: Int by Delegates.notNull<Int>()
fun toPerson(): Person = Person(this.name, this.age)
}
fun person(config: PersonDSL.() -> Unit): Person{
val dsl = PersonDSL()
dsl.config()
return dsl.toPerson()
}
fun main(){
val person = person {
name = "John"
age = 25
}
println(person) // Person(name=John, age=25)
}
But why do that?