kotlinx.serialization question for specific case - kotlinx.serialization

I have following data class
#Serializable
data class TestClass(
val id: Int,
val content: String)
and following possible JSONs
{"id" = "1", "content": "1" }
{"id" = "2", "content": {"subcontent1": "subvalue1"} }
{"id" = "3", "content": {"subcontent2": "subvalue2"} }
Exact structure of content is unknown and may change. Is it possible to deserialize such json into TestClass ?
If I use
Json {
ignoreUnknownKeys = true
isLenient = true
}.decodeFromString<TestClass>(inputJsonString)
I get following exception
Unexpected JSON token at offset 122: Expected string or non-null literal
Could you please provide any ideas on what is the best way to overcome this?
Do I have to write custom serializer or it can be done easier somehow?

I have found an answer on my question.
Need to implement custimn serializer
object AnyToStringSerializer : KSerializer<String> {
override fun deserialize(decoder: Decoder): String {
val jsonInput = decoder as? JsonDecoder ?: error("Can be deserialized only by JSON")
val json = jsonInput.decodeJsonElement().jsonObject.toString()
return json
}
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("anyString", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: String) {
val jsonElement = Json.parseToJsonElement(value)
val jsonEncoder = encoder as? JsonEncoder ?: error("Can be deserialized only by JSON")
jsonEncoder.encodeJsonElement(jsonElement)
}
}
And then use it for the field you want to be raw string
#SerialName("x")
#Serializable(with = AnyToStringSerializer::class)
val X: String,

Related

Exceptions not captured in opencsv parsing

I'm trying to parse a csv file and map it onto a data class. I've setup some validations for the columns and I'm testing it by sending incorrect values for those columns. opencsv throws a generic exception
Basic instantiation of the given bean type (and subordinate beans created through recursion, if applicable) was determined to be impossible.
Code details
Data class:
data class UserInfo(
#CsvBindByName(column = "Id", required = true) val id: Long,
#CsvBindByName(column = "FirstName", required = true) val firstName: String,
#CsvBindByName(column = "LastName", required = true) val lastName: String,
#CsvBindByName(column = "Email", required = true) val email: String,
#CsvBindByName(column = "PhoneNumber", required = true) val phoneNumber: String,
#PreAssignmentValidator(
validator = MustMatchRegexExpression::class, paramString = "^[0-9]{10}$")
#CsvBindByName(column = "Age", required = true)
val age: Int
)
csv parsing logic
fun uploadCsvFile(file: MultipartFile): List<UserInfo> {
throwIfFileEmpty(file)
var fileReader: BufferedReader? = null
try {
fileReader = BufferedReader(InputStreamReader(file.inputStream))
val csvToBean = createCSVToBean(fileReader)
val mappingStrategy: HeaderColumnNameMappingStrategy<Any> =
HeaderColumnNameMappingStrategy<Any>()
mappingStrategy.type = UserInfo::class.java
val userInfos = csvToBean.parse()
userInfos.stream().forEach { user -> println("Parsed data:$user") }
csvToBean.capturedExceptions.stream().forEach { ex -> println(ex.message) }
return userInfos
} catch (ex: Exception) {
throw CsvImportException("Error during csv import")
} finally {
closeFileReader(fileReader)
}
}
private fun createCSVToBean(fileReader: BufferedReader?): CsvToBean<UserInfo> =
CsvToBeanBuilder<UserInfo>(fileReader)
.withType(UserInfo::class.java)
.withThrowExceptions(false)
.withIgnoreLeadingWhiteSpace(true)
.build()
I'm looking for the proper error message for the validation / missing field so that I can communicate it to the error response.

Get value from sorting data in Kolin

My task is to return ArrayList of type transactionsList
First I have to parse date in string and then stream it (ascending)
I know how to do that but sortedWith give back type Unit not Array.
val cmp = compareBy<transactionsList> { LocalDate.parse(it.date,
DateTimeFormatter.ofPattern("dd.MM.yyyy.")) }
val sortedList: List<transactionsList> = ArrayList()
acountTransactionList
. sortedWith(cmp)
.forEach(::println)
return acountTransactionList
I cannot store data from that sort because it gives me type Unit.
The following works as intended (the issue is that forEach() method returns Unit, not each object):
fun main() {
val acountTransactionList: ArrayList<transactionsList> = arrayListOf(transactionsList("10.10.2010."),
transactionsList("10.10.2000."),
transactionsList("10.09.2010."),
transactionsList("10.11.2010."),
transactionsList("11.11.2010."),
transactionsList("10.10.2001."))
val cmp = compareBy<transactionsList> {
LocalDate.parse(it.date, DateTimeFormatter.ofPattern("dd.MM.yyyy."))
}
val sortedList: List<transactionsList> = acountTransactionList.sortedWith(cmp)
println(sortedList)
}
data class transactionsList(val date: String)

Kotlin iterator to check if payload list have an id/projectId or not, returning false when there is no attributes?

I have an issue where i have a method where i am checking the payload has the attributes or not. When i am sending my payload i want to check that the user dont have inserted attributes which not allowed in the payload.
My entity class:
#Entity
data class ProjectAssociated(
#Id
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Column(columnDefinition = "BINARY(16)")
var id: UUID? = null,
#Column(columnDefinition = "BINARY(16)")
var projectId: UUID? = null,
#Column(columnDefinition = "BINARY(16)")
var associatedProjectId: UUID? = null
)
My Service class:
fun addAssociatedProjectByProjectId(
projectId: UUID,
projectAssociatedList: MutableList<ProjectAssociated>
): MutableList<ProjectAssociated> {
if (projectAssociatedList.isNotEmpty()) {
println(projectAssociatedList)
if (!projectAssociatedList.map { it.id }.isNullOrEmpty()) {
val errorMessage = "Not allowed to provide parameter 'id' in this request"
throw UserInputValidationException(errorMessage)
}
if (!projectAssociatedList.map { it.projectId }.isNullOrEmpty()) {
val errorMessage = "Not allowed to provide parameter 'projectId' in this request"
throw UserInputValidationException(errorMessage)
}
val checkIds = projectAssociatedList.map {
projectRepository.existsById(it.associatedProjectId)
}
if (checkIds.contains(false)) {
val errorMessage = "One or more ID 'associatedProjectId' not exists"
throw UserInputValidationException(errorMessage)
}
}
return projectAssociatedList.map {
projectAssociatedRepository.save(
ProjectAssociated(
null,
projectId,
it.associatedProjectId
)
)
}.toMutableList()
}
My Controller class:
#ApiOperation("Add associated Projects to a specific Project")
#PostMapping(path = ["/project-associated"], consumes = [MediaType.APPLICATION_JSON_VALUE])
fun createAssociatedProjectList(
#ApiParam("The id of the Project", required = true)
#RequestParam("id")
id: UUID,
#ApiParam("JSON object representing the ProjectAssociated")
#RequestBody projectAssociated: MutableList<ProjectAssociated>
): ResponseEntity<WrappedResponse<MutableList<ProjectAssociated>>> {
val createdProjectAssociatedList = projectService.addAssociatedProjectByProjectId(id, projectAssociated)
return ResponseEntity
.status(201)
.location(URI.create("$id/project-associated"))
.body(
ResponseDto(
code = 201,
data = PageDto(list = mutableListOf(createdProjectAssociatedList))
).validated()
)
}
But when i try to send this payload with the project id in #RequestParam:
[
{
"associatedProjectId": "7fe40f90-5178-11ea-9136-1b65a920a5d9"
},
{
"associatedProjectId": "7fe8aaaa-5178-11ea-9136-1b65a920a5d9"
}
]
I have a custom exception where i tell the user if projectId or the id is in the payload that is now allowed to have it in the payload. When i try to POST the payload example above it tells me that projectId or id is in the request? How can that be?
I also printed out the list before if checks:
[ProjectAssociated(id=null, projectId=null, associatedProjectId=7fe40f90-5178-11ea-9136-1b65a920a5d9), ProjectAssociated(id=null, projectId=null, associatedProjectId=7fe8aaaa-5178-11ea-9136-1b65a920a5d9)]
What am I doing wrong?
Thanks for the help!
In the block projectAssociatedList.map { it.id } you are mapping your list to something like [null, null] and it is not null or empty.
So, the complete condition !projectAssociatedList.map { it.id }.isNullOrEmpty() returns true.
If you want to continue using the same logic, you should use !projectAssociatedList.mapNotNull { it.id }.isNullOrEmpty() instead.
The mapNotNull function will filter the null values and output a list just with the not null values. If there is only null values, the list will be empty.
But, a simpler and expressive way to check if there is any not null attribute in a list of objects could be projectAssociatedList.any { it.id != null }

How do fetch the state with custome query? Corda application using Spring boot webserver- error while fetching the result

I have created the IOU in corda applicatiion, the IOU has ID,xml payload in body, partyName. NOW, i want to fetch the state with custome query that is basis on ID. NOTE- i am not using linearID.
Below is my API call- which gives me syntax error on. Can someone please correct me, what is the wrong thing that i am doing.
#GetMapping(value = ["getIous"],produces = [ MediaType.APPLICATION_JSON_VALUE])
private fun getTransactionOne(#RequestParam(value = "payloadId") payloadId: String): ResponseEntity<List<IOUState>> {
val generalCriteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL)
val results = builder { IOUState::iouId.equal(payloadId)
val customCriteria = QueryCriteria.VaultCustomQueryCriteria(results)}
val criteria = customCriteria.and(customCriteria)
val res = proxy.vaultQueryBy<IOUState>(criteria)
return ResponseEntity.ok(res)
}
I think the issue is because VaultCustomQueryCriteria is applicable only to StatePersistable objects. So you should use PersistentIOU instead of IOUState. Also, I could see incorrect use of brackets. Here is how your code should look like:
#GetMapping(value = ["getIous"],produces = [ MediaType.APPLICATION_JSON_VALUE])
private fun getTransactionOne(#RequestParam(value = "payloadId") payloadId: String): ResponseEntity<List<IOUState>> {
val generalCriteria = QueryCriteria.VaultQueryCriteria(Vault.StateStatus.ALL)
val results = builder {
val idx = IOUSchemaV1.PersistentIOU::iouId.equal(payloadId);
val customCriteria = QueryCriteria.VaultCustomQueryCriteria(idx)
val criteria = generalCriteria.and(customCriteria)
proxy.vaultQueryBy<IOUState>(criteria);
}
return ResponseEntity.ok(results)
}

Filtering multiple times on one dictionary

I currently run this code:
searchterm = "test"
results = resultsArray.filter { $0.description.contains (searchterm!) }
My question is how do I search in company_name or place or any other field in my model and add it to the results.
Do I need to use filters together and then append the results to a new variable instance of my model?
EDIT:
If "test" is in company_name, place and description. I want all three results returned. However, if "test" is only in place, I need only place to be returned.
EDIT2:
This is an example of my model return. Is this a dictionary or an array? I'm sorry I dont 100% percent know the difference. I know ' "this": is ' what a dictionary looks like, however because there were [] brackets around them, I thought that made it an array...
struct GraphData {
var description: String
var company_name: String
var places: String
init(description: String, company_name: String, places: String){
self.description = description
self.company_name = company_name
self.places = places
}
func toAnyObject() -> Any {
print("return")
return [
"description": description,
"company_name": company_name,
"places": places,
]
}
The easiest way to do this would be to create a custom contains method in your model which can you can use to match the search term against any property in the model:
class YourModel {
var company_name: String
var description: String
var place: String
// ...
func contains(_ searchTerm: String) -> Bool {
return self.company_name.contains(searchTerm)
|| self.description.contains(searchTerm)
|| self.place.contains(searchTerm)
}
}
You can then simply filter using your custom method:
let searchTerm = "test"
let results = resultsArray.filter { $0.contains(searchTerm) }
Is this resultsArray a dictionary or an array?
You can do something like this
let searchTerm = "test"
let filter = resultsArray.filter{ $0.company_name!.contains(searchTerm) || $0.place!.contains(searchTerm) }
Edit
class TestClass: NSObject {
var place: String?
var company_name: String?
func contain(searchTerm: String) -> [String] {
var result = [String]()
if let placeVal = place, placeVal.contains(searchTerm) {
result.append(placeVal)
}
if let companyVal = company_name, companyVal.contains(searchTerm) {
result.append(companyVal)
}
return result
}
}
let searchTerm = "test"
let filter = resultsArray.map { $0.contain(searchTerm: searchTerm) }

Resources