POJO class mismatch - kotlin

I have the following class User that extends the BaseResponse class. I
am getting a type mismatch error:
Required => String
Found => String.Companion
for return apiKey
package com.touchsides.rxjavanetworking.network.model
import com.google.gson.annotations.SerializedName
class User: BaseResponse()
{
#SerializedName("api_key")
val apiKey = String
fun getApiKey(): String
{
return apiKey
}
}
abstract class BaseResponse(var error: String?=null)
{
}
How is the current implementation of this wrong

You used = instead : while declaration of api_key (apiKey = String). Which actually means you are initialising api_key with String.Companion Object.
And you don't need to create getApiKey() (getter) method as by default you will have getter method for your properties.
class User : BaseResponse() {
#SerializedName("api_key")
var apiKey: String? = null
private set
}
abstract class BaseResponse(var error: String? = null)
in fact you can use data class for this purposes
data class User(#SerializedName("api_key") val apiKey: String):BaseResponse()
fun main(args: Array<String>) {
Gson().fromJson<User>("{\"api_key\":\"my api key\"}", User::class.java).let {
println(it.apiKey)
}
}

A complete answer is that your code should look like this:
class User: BaseResponse()
{
#SerializedName("api_key")
lateinit var apiKey: String // must be set by something before being read
}
abstract class BaseResponse(var error: String?=null) {
}
You do not need a default value for the apiKey property if you intend to set it via deserialization later, if not then you should also add a default value as below. The getApiKey() method is removed because you do not need that in Kotlin, all properties have automatically generated getters built-in and by adding your own you would end up with a conflict between the generated getter and the one you manually created (two methods with the same name, same signature).
If you do need a default value for apiKey then stay with a var so that deserialization can work (if you intend to do that) and add a default empty string or make it a nullable string and set it to null.
class User: BaseResponse()
{
#SerializedName("api_key")
var apiKey: String = "" // if you want a default regardless, or make it nullable and null
}
abstract class BaseResponse(var error: String?=null) {}

You're stuck with the way Java do things. In kotlin when defining Getter and Setter, you don't have to write them yourself. Once you declare a variable, both methods would be automatically created.
EDIT: So delete the getter in your POJO class.

Related

How to change return type based on a function input which is a class name?

I have multiple data classes and each class has a corresponding class containing more info. I want to write a function in which I should be able to pass an identifier (table name corresponding to the data class). Based on this identifier, object of the corresponding class should be made, the value changed and this object should be returned as output of the function. I have written a simplified version of it on playground but I am unable to get it to work. Any help is appreciated.
class someClass(
)
class objectForSomeClass(
var value: String
)
class someOtherClass(
)
class objectForSomeOtherClass(
var value: String
)
class doSomething() {
companion object {
val classMap = mapOf(
"someClass" to objectForSomeClass::class,
"someOtherClass" to objectForSomeOtherClass::class,
)
}
// Create a map of class name to a new object based on the class name input
fun dummyFun(className: String, valueInput: String): Map<String, kotlin.Any> {
var returnObject = mutableListOf<Pair<String, kotlin.Any>>()
when(className) {
"SOME_CLASS" -> {
returnObject = mutableListOf<Pair<String, justDoIt.classMap["someClass"]()>>()
}
"SOME_OTHER_CLASS" -> {
returnObject = Map<String, justDoIt.classMap["someOtherClass"]()>
}
}
returnObject[className].value = valueInput
return returnObject
}
}
fun main() {
var obj = doSomething()
var t = obj.dummyFun("SOME_CLASS", "Value to be inserted")
// do something with t
}
Not knowing more about your classes (the ones in your code are not data classes – a data class in Kotlin is a specific type of class) I still think a lot could be simplified down to maybe even this:
fun createObject(className: String, value: String): Any? {
return when (className) {
"SomeClass" -> ObjectForSomeClass(value)
"SomeOtherClass" -> ObjectForSomeOtherClass(value)
// ...
else -> null
}
}
Additionally:
The classMap is not necessary, you can hard-code the cases in the when clause as in my example. There is also no need for reflection, which you would need to create instances from SomeType::class.
With getting rid of classMap you also do not need the companion object holding it anymore, and then you are left with one function for creating instances of your classes, and this function does not have to be in a class. You might put it into a singleton class called object in Kotlin (https://kotlinlang.org/docs/object-declarations.html#object-expressions)
Data classes in Kotlin: https://kotlinlang.org/docs/data-classes.html
You could maybe also replace each class someClass & class objectForSomeClass pair with a class someClass with a companion object.

How to make field required in kotlin DSL builders

In Kotlin, when creating a custom DSL, what is the best way to force filling required fields inside the builder's extension functions in compile time. E.g.:
person {
name = "John Doe" // this field needs to be set always, or compile error
age = 25
}
One way to force it is to set value in a function parameter instead of the body of the extension function.
person(name = "John Doe") {
age = 25
}
but that makes it a bit more unreadable if there are more required fields.
Is there any other way?
New type inference enables you to make a null-safe compile-time checked builder:
data class Person(val name: String, val age: Int?)
// Create a sealed builder class with all the properties that have default values
sealed class PersonBuilder {
var age: Int? = null // `null` can be a default value if the corresponding property of the data class is nullable
// For each property without default value create an interface with this property
interface Named {
var name: String
}
// Create a single private subclass of the sealed class
// Make this subclass implement all the interfaces corresponding to required properties
private class Impl : PersonBuilder(), Named {
override lateinit var name: String // implement required properties with `lateinit` keyword
}
companion object {
// Create a companion object function that returns new instance of the builder
operator fun invoke(): PersonBuilder = Impl()
}
}
// For each required property create an extension setter
fun PersonBuilder.name(name: String) {
contract {
// In the setter contract specify that after setter invocation the builder can be smart-casted to the corresponding interface type
returns() implies (this#name is PersonBuilder.Named)
}
// To set the property, you need to cast the builder to the type of the interface corresponding to the property
// The cast is safe since the only subclass of `sealed class PersonBuilder` implements all such interfaces
(this as PersonBuilder.Named).name = name
}
// Create an extension build function that can only be called on builders that can be smart-casted to all the interfaces corresponding to required properties
// If you forget to put any of these interface into where-clause compiler won't allow you to use corresponding property in the function body
fun <S> S.build(): Person where S : PersonBuilder, S : PersonBuilder.Named = Person(name, age)
Use case:
val builder = PersonBuilder() // creation of the builder via `invoke` operator looks like constructor call
builder.age = 25
// builder.build() // doesn't compile because of the receiver type mismatch (builder can't be smart-casted to `PersonBuilder.Named`)
builder.name("John Doe")
val john = builder.build() // compiles (builder is smart-casted to `PersonBuilder & PersonBuilder.Named`)
Now you can add a DSL function:
// Caller must call build() on the last line of the lambda
fun person(init: PersonBuilder.() -> Person) = PersonBuilder().init()
DSL use case:
person {
name("John Doe") // will not compile without this line
age = 25
build()
}
Finally, on JetBrains open day 2019 it was said that the Kotlin team researched contracts and tried to implement contracts that will allow creating safe DSL with required fields. Here is a talk recording in Russian. This feature isn't even an experimental one, so
maybe it will never be added to the language.
In case you're developing for Android I wrote a lightweight linter to verify mandatory DSL attributes.
To solve your use case you will only need to add an annotation #DSLMandatory to your name property setter and the linter will catch any place when it is not assigned and display an error:
#set:DSLMandatory
var name: String
You can take a look here:
https://github.com/hananrh/dslint/
Simple, throw an exception if it's not defined in your DLS after the block
fun person(block: (Person) -> Unit): Person {
val p = Person()
block(p)
if (p.name == null) {
// throw some exception
}
return p
}
Or if you want to enforce it at build time, just make it return something useless to the outer block if not defined, like null.
fun person(block: (Person) -> Unit): Person? {
val p = Person()
block(p)
if (p.name == null) {
return null
}
return p
}
I'm guessing your going off this example so maybe address would be the better example case:
fun Person.address(block: Address.() -> Unit) {
// city is required
var tempAddress = Address().apply(block)
if (tempAddress.city == null) {
// throw here
}
}
But what if we wanted to ensure everything was defined, but also wanted to let you do it in any order and break at compile time. Simple, have two types!
data class Person(var name: String = null,
var age: Int = null,
var address: Address = null)
data class PersonBuilder(var name: String? = null,
var age: Int? = null,
var address: Address? = null)
fun person(block: (PersonBuilder) -> Unit): Person {
val pb = PersonBuilder()
block(p)
val p = Person(pb.name, pb.age, pb.address)
return p
}
This way, you get to you the non-strict type to build, but it better be null-less by the end. This was a fun question, thanks.

Java annotation implementation to Kotlin

I am trying to replicate the implementation of #Age constraint(found it on online) from Java to Kotlin, I copied the java code base and used the IDE to convert it Kotlin code.
Java code
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
#Retention(RUNTIME)
#Repeatable(Age.List.class)
#Documented
#Constraint(validatedBy = { })
public #interface Age {
String message() default "Must be greater than {value}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
long value();
#Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
#Retention(RUNTIME)
#Documented
#interface List {
Age[] value();
}
}
Corresponding Kotlin code generated by Intellij
#Target(AnnotationTarget.*)
#Retention(RUNTIME)
#Repeatable(Age.List::class)
#Documented
#Constraint(validatedBy = arrayOf())
annotation class Age(
val value: Long,
val message: String = "Must be greater than {value}",
val groups: Array<KClass<*>> = arrayOf(),
val payload: Array<KClass<out Payload>> = arrayOf()) {
#Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.FIELD,
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.CONSTRUCTOR,
AnnotationTarget.VALUE_PARAMETER,
AnnotationTarget.TYPE)
#Retention(RUNTIME)
#Documented
annotation class List(vararg val value: Age)
}
The Kotlin code results in error stating "Members are not allowed in annotation class". Does moving the annotation class List out from Age should resolve the issue? Is there any other way to implement an annotation class within another one?
Thank You.
Yes, you need to move List out of Age. The restriction on having nested classes inside annotations will very likely be removed in a future version of Kotlin; it's more of a design oversight than an essential issue.

Cannot return a String in Kotlin when don't "private"

Why it error when i make userName is public:
Error:(2, 5) Kotlin: Platform declaration clash: The following
declarations have the same JVM signature
(getUserName()Ljava/lang/String;):
fun (): String defined in User
fun getUserName(): String defined in User
Error:(4, 5) Kotlin: Platform declaration clash: The following declarations have the same
JVM signature (getUserName()Ljava/lang/String;):
fun (): String defined in User
fun getUserName(): String defined in User
But i make userName is private is working fine
class User{
/*private*/ var userName: String = "Emily"
fun getUserName(): String{
return userName
}
}
fun main(args: Array<String>){
val User = User()
print(User.getUserName())
}
By making your userName property public, Kotlin will create corresponding getUserName() and setUserName() functions for you. When it does this, writing your own getUserName() is redundant - the same function with the same signature is effectively present twice - and the compiler won't allow it.
If you want the userName field to be a public property (with a generated getter and setter), then you can't also write the getter yourself. This would be adequate:
var userName: String = "Emily"
If you wanted userName to have a public getter and a private setter (which seems like what you intended), this is the Kotlin way to do that:
var userName: String = "Emily"
private set
And finally, you could still create custom accessors on a property (e.g., if you wanted extra logic, such as to return it lowercased). The Kotlin way to do that looks like this:
private var _userName: String = "Emily"
var userName: String
get() = _userName.toLowerCase()
set(value) { _userName = value }
Also, note that the way you access the property is different depending on whether you're accessing it from Kotlin or Java. From Kotlin, you just write user.userName, but in Java, you'd write user.getUserName().
When you define var userName you are really defining a property, not just a field. Along with the property comes an implicit getUserName() and setUserName() method. By adding your own getUserName(), you are shadowing the one Kotlin is creating for you automatically.
You can safely drop your getUserName() and the make your field non-private and it should work fine. The idiomatic way to write your code would be something like this:
class User {
var userName: String = "Emily"
}
fun main(args: Array<String>){
val user = User() // Note changed val from User to user.
print(user.userName) // Note, this really calls the getter
}
In Kotlin, a setter and getter is being created for every property (unless visibility prohibits it), e.g. for your userName which happens to be named exactly like the one you provided in addition: getUserName(). The result is a name clash. Note that for var, also setters are generated. Use val for read-only properties.
Actually, you don't need explicit getters like this. Simply do:
class User{
/*private*/ var userName: String = "Emily"
}
//use property syntax
val user = User()
print(user.userName)
I just want to add more about private field. When you declare a field with private modifier, Kotlin won't generate getter/setter
class User {
private var userName = "Na"
fun getUserName(): String {
return userName;
}
fun setUserName(v: String) {
userName = v
}
}
And when you declare above methods (getter and setter) then these are treated as User Defined methods.

Passing parameters to a custom getter in kotlin

I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}