Kotllin create an Arraylist of an Object - kotlin

I want to create an array list of BaseObject getting the data from List< Allparkingquery> which has a same params as BaseObject but different class names
Here is the base BaseObject
data class BaseObject (
#SerializedName("queryfor") var queryfor : String,
#SerializedName("whichitem") val whichitem : String,
#SerializedName("Latitude") val latitude : String,
#SerializedName("Longitude") val longitude : String,
#SerializedName("DateCreated") val dateCreated : String,
#SerializedName("NumberQueried") val numberQueried : String,
#SerializedName("CurrentState") var currentState : String
)
Here is the array of #SerializedName("allparkingquery") val allparkingquery : List,
data class Allparkingquery (
#SerializedName("queryfor") val queryfor : String,
#SerializedName("whichitem") val whichitem : String,
#SerializedName("Latitude") val latitude : String,
#SerializedName("Longitude") val longitude : String,
#SerializedName("DateCreated") val dateCreated : String,
#SerializedName("NumberQueried") val numberQueried : String,
#SerializedName("CurrentState") val currentState : String
)
Here is where am trying to loop List< Allparkingquery> as populate the data into
List< BaseObject >
So the challange is baseList.add(item) is showing an error. See below
var baseList: List<BaseObject> = ArrayList<BaseObject>()
response.response_data.history[0].allparkingquery.forEachIndexed { index, item ->
baseList.add(item)
}

The reason this is happening is that despite the similarities, BaseObject and Allparkingquery are not related as Allparkingquery does not inherit from BaseObject.
The justification for having a base object is lacking from your example so I'm assuming Allparkingquery will have a field that will differentiate it from BaseObject in the future, so going off that what you need to do is change BaseObject to an abstract class or an interface and have Allparkingquery inherit from it.
abstract class BaseObject {
#SerializedName("queryfor") abstract var queryfor : String,
#SerializedName("whichitem") abstract val whichitem : String,
#SerializedName("Latitude") abstract val latitude : String,
#SerializedName("Longitude") abstract val longitude : String,
#SerializedName("DateCreated") abstract val dateCreated : String,
#SerializedName("NumberQueried") abstract val numberQueried : String,
#SerializedName("CurrentState") abstract var currentState : String
}
class Allparkingquery(
override var queryfor : String,
override val whichitem : String,
override val latitude : String,
override val longitude : String,
override val dateCreated : String,
override val numberQueried : String,
override var currentState : String
) : BaseObject()

Related

How get data from dto?

I have this DTO in Kotlin
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
sealed class InspirationDTO {
abstract val id: Long
#JsonTypeName("DishOfTheDay")
data class DishOfTheDay(
#JsonProperty("dishOfTheDay")
val dishOfTheDay: DishOfTheDayDTO,
override val id: Long,
) : InspirationDTO()
#JsonTypeName("InspirationScreenContinuousSlider")
data class InspirationScreenContinuousSlider(
#JsonProperty("name")
val inspirationScreenContinuousSlider: InspirationScreenContinuousSliderDTO,
override val id: Long,
) : InspirationDTO()
#JsonTypeName("InspirationScreenLink")
data class InspirationScreenLink(
#JsonProperty("inspirationScreenLink")
val inspirationScreenLink: InspirationScreenLinkDTO,
override val id: Long,
) : InspirationDTO()
#JsonTypeName("InspirationScreenPagingSlider")
data class InspirationScreenPagingSlider(
#JsonProperty("inspirationScreenPagingSlider")
val inspirationScreenPagingSlider: InspirationScreenPagingSliderDTO,
override val id: Long,
) : InspirationDTO()
#JsonTypeName("InspirationScreenRecentlyViewedSlider")
data class InspirationScreenRecentlyViewedSlider(
#JsonProperty("inspirationScreenRecentlyViewedSlider")
val inspirationScreenRecentlyViewedSlider: InspirationScreenRecentlyViewedSliderDTO,
override val id: Long,
) : InspirationDTO()
#JsonTypeName("InspirationScreenTagsSlider")
data class InspirationScreenTagsSlider(
#JsonProperty("inspirationScreenTagsSlider")
val inspirationScreenTagsSlider: InspirationScreenTagsSliderDTO,
override val id: Long,
) : InspirationDTO()
}
in service I expect that DTO to save all data from it's classes
fun saveDishOfTheDay(inspirationDTO: InspirationDTO) = with(inspirationDTO) {
inspirationFacadeRepo.saveDish(DishOfTheDayEntity(id = id, title = inspirationDTO.DishofTheDay.title))
}
this part I need to get inspirationDTO.DishofTheDay.title
but inspirationDTO from this DTO can't see DishOfTheDay class and it's inner item title
like this
data class DishOfTheDayDTO(
val title: String,
)
so need to get all classes from that DTO and their fields to put in entity fields and save them.

Refer to attribute previously defined in constructor in Kotlin

I was wondering if there is any way to refer to a previously defined property in a constructor in Kotlin. Something like:
data class Order(
val id: String,
val transformedId: String
}
and then when initiating the class, do:
val orderId = getOrderId()
Order(
id = orderId,
transformedId = transform(id)
}
You can do this with a secondary constructor.
data class Order(
val id: String,
val transformedId: String
) {
constructor(id: String): this(id, transform(id))
}
If you want this to be the only way to create the class, you can make the primary constructor private:
data class Order private constructor(
val id: String,
val transformedId: String
) {
constructor(id: String): this(id, transform(id))
}

Avoid repetition of same logic

I have the following data classes:
sealed class ExampleDto
object Type1ExampleDto : ExampleDto()
object Type2ExampleDto : ExampleDto()
data class Type3ExampleDto(val name: Int, val age: Int) : ExampleDto()
data class Type4ExampleDto(val name: Int, val age: Int) : ExampleDto()
data class Type5ExampleDto(val email: String) : ExampleDto()
data class Type6ExampleDto(val name: Int, val age: Int, val email: String) : ExampleDto()
In particular, Type3ExampleDto, Type4ExampleDto and Type6ExampleDto share some common fields but it's important for my business logic to distinguish between types (i.e. even if Type3ExampleDto and Type4ExampleDto are identical, I have to know if I'm in the type3 or type4 case).
In one of my method I have the following call:
when (type) {
is Type3ExampleDto -> myMethod(type.vote, type.text)
is Type4ExampleDto -> myMethod(type.vote, type.text)
is Type6ExampleDto -> myMethod(type.vote, type.text)
else -> null
}
I find very ugly that I'm doing the same operation in all 3 cases and repeating the same line...
It makes sense to made Type3ExampleDto, Type4ExampleDto and Type6ExampleDto an implementation of some kind of interface just because only in this point I'm doing this kind of ugly repetition?
If all three dtos implement the following interface
interface MyInterface{
fun getVote() : Int
fun getText() : String
}
I can write:
if (type is MyInterface) {
myMethod(type.getVote(), type.getText())
}
So, it's acceptable to create this interface just to solve this isolated repetition?
Thanks
Note you can do it much more cleanly like this:
interface NameAndAgeDto {
val name: Int
val age: Int
}
data class Type3ExampleDto(override val name: Int, override val age: Int) : ExampleDto(), NameAndAgeDto
if (type is NameAndAgeDto) {
myMethod(type.name, type.age)
}
Whether it's "acceptable" is opinion. Looks fine to me.
You may change your model to have your logic based on behaviour instead of inheritance.
This way of modelling is based on principles of (but ain't exactly) Strategy Design Pattern.
interface HasName {
val name: String
}
interface HasAge {
val age: Int
}
interface HasEmail {
val email: String
}
object Type1
object Type2
data class Type3(
override val name: String,
override val age: Int
) : HasName, HasAge
data class Type4(
override val name: String,
override val age: Int
) : HasName, HasAge
data class Type5(
override val email: String
) : HasEmail
data class Type6(
override val name: String,
override val age: Int,
override val email: String
) : HasName, HasAge, HasEmail
// Then you can pass any object to it.
fun main(obj: Any) {
// Koltin type-casts it nicely to both interfaces.
if (obj is HasName && obj is HasAge) {
myMethod(text = obj.name, vote = obj.age)
}
}
fun myMethod(vote: Int, text: String) {
}
If you still want all the types to belong to some parent type, you can use marker interface (without any methods).
interface DTO
interface HasName {
val name: String
}
interface HasAge {
val age: Int
}
interface HasEmail {
val email: String
}
object Type1 : DTO
object Type2 : DTO
data class Type3(
override val name: String,
override val age: Int
) : HasName, HasAge, DTO
data class Type4(
override val name: String,
override val age: Int
) : HasName, HasAge, DTO
data class Type5(
override val email: String
) : HasEmail, DTO
data class Type6(
override val name: String,
override val age: Int,
override val email: String
) : HasName, HasAge, HasEmail, DTO
// Here, it is DTO instead of Any
fun main(obj: DTO) {
if (obj is HasName && obj is HasAge) {
myMethod(text = obj.name, vote = obj.age)
}
}
And use sealed class instead of marker interface if you need classes as enum.
In that case, when over sealed class is exhaustive with all options without null ->.

Kotlin Data class setter using class fields

I have a redis entity using a kotlin data class and its Id should be a combination of few other fields from the same class.
Can this be achieved by defining setter for Id field instead of computing it outside of data class?
#RedisHash("Game")
data class Game(
#Id
val generatedId: String = "Default_ID",
val name: String,
val location: String,
val homeTeam: String,
val awayTeam: String
)
// want something like this
var generatedId : String = "DEFAULT_ID"
get() = "${name}${location}"
// or even better
var generated_Id : String = "${name}${location}"
Did you try to do something like this?
#RedisHash("Game")
data class Game(
val name: String,
val location: String,
val homeTeam: String,
val awayTeam: String,
#Id
val generatedId: String = "${name}${location}"
)

Access properties of a subclass of the declared object type

I have the following abstract class:
abstract class AbstractBook {
abstract val type: String
abstract val privateData: Any
abstract val publicData: Any
}
and the following class which inherits the AbstactBook class:
data class FantasyBook (
override val type: String = "FANTASY",
override val privateData: FantasyBookPrivateData,
override val publicData: FantasyBookPublicData
) : AbstractBook()
And then there is this class which should include data from any type of AbstractBook:
data class BookState(
val owner: String,
val bookData: AbstractBook,
val status: String
)
If I have an instance of BookState, how do I check which type of Book it is and then access the according FantasyBookPrivateData, and FantasyBookPublicData variables?
I hope I described my issue well & thanks in advance for any help!
What you describe is a sealed class:
sealed class Book<T, K> {
abstract val type: String
abstract val privateData: T
abstract val publicData: K
data class FantasyBook(
override val type: String = "FANTASY",
override val privateData: String,
override val publicData: Int) : Book<String, Int>()
}
and in your data class you can do pattern matching like this:
data class BookState(
val owner: String,
val bookData: Book<out Any, out Any>,
val status: String) {
init {
when(bookData) {
is Book.FantasyBook -> {
val privateData: String = bookData.privateData
}
}
}
}
to access your data in a type-safe manner. This solution also makes type redundant since you have that information in the class itself.
I agree with #Marko Topolnik that this seems like a code smell, so you might want to rethink your design.
interface AbstractBook<T , U> {
val privateData: T
val publicData: U
}
data class FantasyBook (
override val privateData: FantasyBookPrivateData,
override val publicData: FantasyBookPublicData
) : AbstractBook<FantasyBookPrivateData , FantasyBookPublicData>
data class BookState(
val owner: String,
val bookData: AbstractBook<*, *>,
val status: String
)
if(bookState.bookData is FantasyBook) {
// Do stuff
}
Creating a type variable is a weak type language writing style. You should use generic class.