No value passed for parameter 'info' in data class - kotlin

I have a data class
data class TaxEngineModel(
#Id
val Id: String = "",
val environment: String = "",
val tDescription: String = "",
val EndPoint: String = "",
val Type: String = "",
val info: infoModel,
)
when I want to create an object, I got an error "No value passed for parameter 'info'", how to fix this issue?
val model = TaxEngineModel()

As the error hints: You must pass a value for info or make info nullable. You have default values for all other backfields in your class, but not for info.
Pass a value:
val model = TaxEngineModel(info = someInfoModel)
or make info nullable:
...
val Type: String = "",
val info: infoModel?, // you could optionally assign null as default here
)
or define a default value:
...
val Type: String = "",
val info: infoModel = someInfoModel, // you could maybe create InfoModel here?
)
However in the later case, you'd need a global constant or something else the constructor has access to.

Related

How manage data classes with empty data in retrofit?

I want to send to the API only the data that I indicate in my data class.
data class UserRequestDTO(
val name: String = "",
val surname: String = ""
)
My empty class
val userDTO = UserRequestDTO()
MyService.getService().users()
My request
#POST("/vo/search")
fun users(
#Body userRequestDTO: UserRequestDTO
): Call<ResponseDTO>
But the following json is being sent:
{"name": "", "surname": ""}
How can I have a class in which I only send the data that I fill in? don't want any data to be sent, and if for example I fill in the name, I don't want the last name to be sent
Making them optional should result in not sending them:
data class UserRequestDTO(
val name: String? = null,
val surname: String? = null
)

How to assign value from one data class to another data class

I have two data class, and after I assign value to attribute in infoModel, I want assign them to infoArchiveModel which has the same fields, in this case, id, env, description and endpoint in infoArchiveModel should be same as those in infoModel , how can I do that?
data class infoModel(
#Id
val id: String = "",
val environment: String = "",
val description: String = "",
val endPoint: String = "",
)
data class infoArchiveModel(
#Id
val id: String = "",
val environment: String = "",
val description: String = "",
val endPoint: String = "",
val date: String = " "
)
A data class can also declare a secondary constructor, just like this:
data class infoArchiveModel(
#Id
val id: String = "",
val environment: String = "",
val description: String = "",
val endPoint: String = "",
val date: String = " "
) {
constructor(model: infoModel):
this (model.id, model.environment, model.description, model.endPoint)
}
//use this constructor
val model: infoModel = ...
val archiveModel = infoArchiveModel(model)
BTW, class names should always start with a capital case.

Exclude non-null properties when serializing a Kotlin data class

I often will create a data class in Kotlin that is used internally for data models. Example:
data class MyDataModel(
var id: String? = null,
var ownerId: String,
var name: String,
var isPrivate: Boolean = false,
)
I often need to serialize these classes to JSON. The problem is that some of the class properties are not nullable and there are cases where I need to exclude those fields in the serialization. I haven't found a clean and simple way to do that. The solution I currently use is not to use non-nullable properties and then set those that I don't want serialized to null.
Is there another approach?
Solution using kotlinx.serialization:
Define class, including all fields you want to be serialized, mark it as #Serializable
#Serializable
open class MyDataModelSerializable(
open var id: String? = null
)
Make your data class to be its subtype:
data class MyDataModel(
var ownerId: String,
var name: String,
var isPrivate: Boolean = false,
override var id: String? = null
) : MyDataModelSerializable(id)
Serialize instances of MyDataModel class with serializer for MyDataModelSerializable:
val s = serializer<MyDataModelSerializable>()
println(Json.encodeToString(s, MyDataModel(ownerId = "1", name = "2", id = "3", isPrivate = true))) //{"id":"3"}
println(Json.encodeToString(s, MyDataModel(ownerId = "1", name = "2", isPrivate = true))) //{}
println(Json{encodeDefaults = true}.encodeToString(s, MyDataModel(ownerId = "1", name = "2"))) //{"id":null}

Looking for correct kotlinpoet syntax to initialize a PropertySpec.Builder for IntArrays and Array<String> values

Don't see the correct syntax for initializing the Array types to the values from an existing types from within the project, primitive types works fine and programmer defined classes
Target(
AnnotationTarget.FIELD,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.PROPERTY)
#Retention(AnnotationRetention.SOURCE)
annotation class ConfigurableIntArray(
val key: String,
val text: String,
val description: String,
val initialValue: IntArray
)
Class BlockAnnotationTester2(#field:ConfigurableIntArray(
key = UIComponentSettings.MAXIMUM_LENGTH_KEY,
text = UIComponentSettings.MAXIMUM_LENGTH_TEXT,
description = UIComponentSettings.MAXIMUM_LENGTH_DESCRIPTION,
initialValue = [2])
val unusedIntArray: IntArray = intArrayOf(1, 2, 3, 4),
for (data in memberDataIntArray)...`
addProperty(
PropertySpec.builder(TestAnnotationProcessor.INITIAL_VALUE, IntArray::class)
.initializer("intArrayOf(${data.annotation.initialValue.asList()})")
.build()
)
object Member_BlockAnnotationTester2UnusedIntArray {
const val KEY: String =
"configurable_block_detail_ui_component_maximum_length"
const val TEXT: String = "Maximum length"
var INITIAL_VALUE: IntArray = intArrayOf([2]) <-- issue
const val DESCRIPTION: String = "Maximum length of the corresponding UI
component"
}
Can only get it to initialize to static data in plain text literals or the first value
Guessing there is a simpler way but this worked
.initializer("%L", buildCodeBlock {
var lregex =
data.annotation.initialValue.asList().toString()
lregex = lregex.replace("["," ")
lregex = lregex.replace("]"," ")
add("intArrayOf($lregex)")
})

Is there a way to use the default value on a non-optional parameter when null is passed?

For example, if I have the following data class:
data class Data(
val name: String = "",
val number: Long = 0
)
And functions that can return null:
fun newName(): String? {}
fun newNumber(): Long? {}
I know I can use the following to use the value of the functions if they are not null:
val newName = newName()
val newNumber = newNumber()
val data = Data(
if (newName != null) newName else "",
if (newNumber != null) newNumber else 0
)
But is there a way to just use the default value specified in the constructor of the Data class when the values are null?
I could not find anything in the documentation, but I was hoping something like this would work:
val data = Data(newName()?, newNumber()?)
But that does not compile.
You can define a companion object for your data class and overload its invoke operator to use default values when null is passed:
data class Data private constructor(
val name: String,
val number: Long
) {
companion object {
operator fun invoke(
name: String? = null,
number: Long? = null
) = Data(
name ?: "",
number ?: 0
)
}
}
the secondary constructor only supports for the Nullable primitive properties. which means it will result in 2 same constructors if the property is not a primitive type, for example:
data class Data(val name: String) {
constructor(name: String? = null) : this(name ?: "foo");
// ^--- report constructor signature error
}
data class Data(val number: Long = 0) {
constructor(number: Long? = null) : this(number ?: 0)
// ^--- No problem since there are 2 constructors generated:
// Data(long number) and Data(java.lang.Long number)
}
an alternative way is using invoke operator for that, for example:
data class Data(val name: String) {
companion object {
operator fun invoke(name: String? = null) = Data(name ?: "")
}
}
IF the class is not a data class, then you can lazy initializing properties from parameters, rather than define properties on the primary constructor, for example:
class Data(name: String? = null, number: Long? = null) {
val name = name ?: ""
val number = number ?: 0
}
If needed, I can offer another solution:
data class Data(
val inputName: String?,
val inputNumber: Long?
) {
private val name = inputName ?: ""
private val number = inputNumber ?: 0
}