I have a data class in Kotlin that inherits from a Java class, which defines a constructor with 1 argument,
public BaseClass(String userSessionId) {
this.userSessionId = userSessionId;
}
My Kotlin class is defined as this
class DerivedClass(
userSessionId: String,
var other: Other? = null
) : BaseClass(userSessionId) {
I can't define it as a data class because of userSessionId, which Kotlin requires to be a val or var in data classes. However, if I do so, then Retrofit throws an exception because there are 2 members named userSessionId. Is there a way to have a data class inherit from a Java class with a constructor taking arguments? Note that I cannot change the base class.
A possible solution is to define a dummy val to avoid the name clash, but this is less than ideal
data class DerivedClass(
val dummy: String,
var other: Other? = null
) : BaseClass(dummy) {
You can use the transient keyword in Java to ignore a field during serialization, this can be done in Kotlin by using the #Transient annotation on the property instead.
Related
How to get the copy of arraylist of sealed class in android
private var homePageApiResponseList : ArrayList<HomeApiResponseModel> = ArrayList()
Here HomeApiResponseModel is a Sealed class. HomeApiResponseModel is given as Below
sealed class HomeApiResponseModel {
data class HomeCategoryListModel(
var categoryList : MutableList<CategoryModel> = mutableListOf(),
var categoryNameType : String = ""
) : HomeApiResponseModel()
data class HomeBestSellerListModel(
var bestSellerList : MutableList<ChildrenModel> = mutableListOf(),
var bestSellerNameType : String = ""
) : HomeApiResponseModel()
data class HomeMustTryListModel(
var mustTryList : MutableList<ChildrenModel> = mutableListOf(),
var mustTryNameType : String = ""
) : HomeApiResponseModel()
}
Normally arraylist of object copy is easly obtain by anyList.map { it.copy() }
While in sealed class it shows error. How to get a copy of arraylist of sealed class
Thanks
Create an abstract function in the parent. Each child can implement it and call through to their own copy(). The abstract function should have a different name than “copy” to avoid conflicts.
By the way, in your case, a sealed interface is probably a cleaner choice than a sealed class because there is no common functionality between the children. And I suggest avoiding combining mutable collections with var properties. Making something mutable in two different ways adds (usually unnecessary) complexity and more opportunities for bugs.
I have a Generic class.
class GenericsClassExample<T>(
var data: T
)
I have another class which I'm passing in place of T.
data class MyDataClass1(val id: String, val value: String)
And I'm instantiating Generic Class like :
val genericClass = GenericClass<MyDataClass1>()
I would like to know how to access the fields (id and value) from genericClass object without knowing the type of the class I'm passing, i.e. I could also pass another class like MyDataClass1 say MyDataClass2 which also has its own fields.
I want to create custom request parser, i want to do this by annotating fields and getting value by reflection but I can get annotation only from the class field, the code below doesn't work for data class or constructor in a class, any idea what is wrong?
open class RequestParser {
fun getRequestWithTag(): String {
var requestString = "<RequestData>"
val declaredMemberProperties = this::class.declaredMemberProperties
declaredMemberProperties.filter {
it.findAnnotation<RequestField>() != null
}.forEach { filteredMemberProperties ->
requestString += "<${filteredMemberProperties.name.firstLetterToUpperCase()}>${filteredMemberProperties.getter.call(this)}</${filteredMemberProperties.name.firstLetterToUpperCase()}>"
}
requestString += "</RequestData>"
return requestString
}
}
#Retention(AnnotationRetention.RUNTIME)
#Target(
FIELD,
PROPERTY,
PROPERTY_GETTER,
VALUE_PARAMETER,
PROPERTY_SETTER,
CONSTRUCTOR,
FUNCTION)
public annotation class RequestField
//model example
data class RequestTest(
#RequestField val name: String
) : RequestParser()
//using example
RequestTest("name").getRequestWithTag()
An attribute in a data class constructor is many things, a constructor parameter, a getter, a setter and a field. So you need to set use-site targets to express what you actually mean.
class Example(#field:Ann val foo, // annotate Java field
#get:Ann val bar, // annotate Java getter
#param:Ann val quux) // annotate Java constructor parameter
See also https://kotlinlang.org/docs/reference/annotations.html#annotation-use-site-targets
So in your case I would try the following:
data class RequestTest(
#property:RequestField val name: String
) : RequestParser()
With property I am able to get the annotation from this::class.declaredMemberProperties
If you put field you would be able to get it via this::class.java.declaredFields
Is there a way to subclass entities in Room?
I have an car entity
#Entity(tableName = "cars")
data class Car(
#PrimaryKey #ColumnInfo(name = "vin") val vin: String,
val manufacturer: String,
val model: String,
val color: String,
val modelYear: Int,
val trim: String = ""
) {
override fun toString() = String.format("%s %s %s %s", modelYear, manufacturer, model, trim)
}
But I want to move the manufacturer, model, and modelYear to a Vehicle entity and have the Car inherit from it.
I tried creating a Vehicle entity with those fields and use data class Car : Vehicle, but does not compile. The error is This type is final and cannot be inherited
In kotlin, all classes are final by default.
From Docs
The open annotation on a class is the opposite of Java's final: it
allows others to inherit from this class. By default, all classes in
Kotlin are final, which corresponds to Effective Java, 3rd Edition,
Item 19: Design and document for inheritance or else prohibit it.
so you need to add open keyword so use
open class Vehicle(..){...}
then
data class Car(...): Vehicle(..){}
Side Note: if you trying to inherit data classes then simply you cannot inherit data class in Kotlin because method like copy in data class are final which cannot be overridden by the child class (which in this case is data class so it will do it automatically) and it's hard to implement other methods like equals when class hierarchy grows exponentially with different data members though you can avoid all this collision by making non-data parent class or abstract class
I have a data feed that is returning a list that could be either of three types ( Say type A, B and C ). All of the types above share 2 properties, the rest of the properties is specific to the type. I tried using the pattern.
abstract class Parent (val type: String, val id: String)
And
data class TypeA(override val type: String ... )
data class TypeB(override val type: String ... )
I am using Retrofit and trying to deserialize the list to
List<? extends Parent>
which in Kotlin should be
List<out Parent>
However GSON is throwing a deserializing error on instantiating the parent class which is abstract.
java.lang.RuntimeException: Failed to invoke public com.XX.Parent() with no args
Any ideas how I can implement this in Kotlin?
As you have Moshi tagged in your question, I'll give you a way of doing it using MOshi's PolymorphicJsonAdapterFactory. You can basically parse something into different types, depending on the value of the object's property.
First thing you'll do is declared your parent type as a sealed class and have the other types extend from it:
sealed class Parent(val type: String){
data class TypeA(override val type: String, ... ): Parent(type)
data class TypeB(override val type: String, ... ): Parent(type)
}
now you're gonna tell Moshi how to parse Parent objects. You do that registering a PolymorphicJsonAdapterFactory:
val moshi = Moshi.Builder()
.add(PolymorphicJsonAdapterFactory.of(Parent::class.java, "type")
.withSubtype(TypeA::class.java, "typeA")
.withSubtype(TypeB::class.java, "typeB")
.build()
with that, if the value of the property "type" is "typeA", it will deserialize into a TypeA instance. like wise to TypeB, if property "type" is "typeB"
You can look another example here:
https://github.com/square/moshi/blob/master/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java