Kotlin and constructors, initializing - kotlin

Sorry for asking a very newbie Kotlin question, but I'm struggling to understand some of the things related to constructors and intitializing.
I have this class and constructor:
class TestCaseBuilder constructor(
caseTag: String = "Case",
applType: Buy.ApplFor = Buy.ApplFor.PROOFFINANCE,
komnr: String = "5035") {
var caseTag: String = caseTag
var applType: Buy.ApplFor = applType
var komnr: String = komnr
What I'm trying to do here is to have three optional parameters in the constructors, using default values for them. The reason I'm declaring them in the class body is because I need to have access to them from the main class.
Now, this code works. No errors when I run it. But IntelliJ gives the following comment for the variables (ex.: caseTag):
Property is explicitly assigned to parameter caseTag, can be declared
directly in constructor.
What I've found when searching this is examples using an init {}, but the result I've gotten to includes initializing the variables twice, once in the constructor and then in the init {}. Which clearly isn't correct, I'd say?
What's a better what to have (or than having) optional parameters in the constructor, and then creating class variables from them?

You can declare properties directly in primary constructor. That means you can drop explicit declarations in class body:
class TestCaseBuilder constructor(
var caseTag: String = "Case",
var applType: Buy.ApplFor = Buy.ApplFor.PROOFFINANCE,
var komnr: String = "5035")
You can also drop the constructor keyword if your primary constructor does not have any annotations or visibility modifiers (defaults to public).

#JvmOverloads annotation can over load the constructor with different param size
class TestCaseBuilder #JvmOverloads constructor(
var caseTag: String = "Case",
var applType: Buy.ApplFor = Buy.ApplFor.PROOFFINANCE,
var komnr: String = "5035"
)
Then the class got three constructor with optional param
val a = TestCaseBuilder("CaseA")
val b = TestCaseBuilder("CaseB", Buy.ApplFor.SomethingElse)
val c = TestCaseBuilder("CaseB", Buy.ApplFor.SomethingElse, "1111")

Related

Is it possible to nest an enum contains class's properties within an open class?

I've read this thread, it doesn't address my specific case.
Here's my minimal case:
open class BaseCase() {
lateinit var txtNode: UiObject
enum class TextType(val field: UiObject) {
PlainText(txtNode)
}
}
But there's error:
I was wondering if it is possible in Kotlin?
The problem is that txtNode is an instance variable. Different BaseCase instances could have different values. So the enum cannot know which one of them to take.
Let's for simplicity say txtNode is a String instead of an UiObject
Then how would the following code work?
val a = BaseCase()
a.txtNode = "test"
val b = BaseCase()
b.txtNode = "test2"
val c = BaseCase.TextType.PlainText
would c have "test" or "test2" as field? It simply isn't possible.
that's because enum class are final static classes ---> you cannot access non static variables.
for testing -> if you move your variable to companion object the code will work

How to add an "Item" object to an Object ArrayList in kotlin

I have the following class
class Item {
var name: String = ""
constructor(n: String) {
name = n
}
}
On my main activity I have declared this:
var list: ArrayList<Object> = ArrayList<Object>()
When I try to do this
list.add(Item("Hey friend"))
The compiler complains about type mismatch (Object -> Item) which is obviously true but since Item is also an Object, shouldn't this be fine? I'm pretty sure you can do this in Java, whats the alternative?
I need the list to be of type object because I have to store different stuff in there, so changing it is not an option.
The supertype of all types in Kotlin is Any, not Object.
Other things you can improve in var list: ArrayList<Object> = ArrayList<Object>():
make it a val because immutability is preferred
If you need an explicit type declaration, use the interface List<Any
use Kotlin's collection builders listOf()
val items: List<Any> = listOf()`
Also, the class definition can be reduced to
class Item(val name: String) //could even be a data class

ArrayList<AbstractObject> adding objects which extended AbstractObject is not possible. How to fix it?

So I have ArrayList<AbstractObject> which is class type abstract. And I have 2 items which extends AbstractObject. If I use abstractList.add(Object1) it says that ArrayList expects object of type AbstractObject and not Object1. I thought that this is possible. Reason why I want to do this is to use multiple objects with 2 different data in single RecyclerView. (ViewTypes)
abstract class ListItem {
abstract val type: Int
companion object {
const val TYPE_HEADER = 0
const val TYPE_ITEM = 1
}
}
class HeaderItem(val headerTitle: String) : ListItem() {
val type: Int
get() = TYPE_HEADER
}
class ObjectItem(val object: ParseObject) : ListItem() {
val type: Int
get() = TYPE_ITEM
}
Init #1:
var recyclerViewArray: ArrayList<out ListItem> = ArrayList()
This is error if I want to add HeaderItem to this list:
Init #2:
var recyclerViewArray: ArrayList<ListItem> = ArrayList()
This says Type mismatch. Tried with as but as is yellowed with message This cast can never succeed.
It is possible and it works fine. If in some expression Kotlin infers the type wrong, you can always specify it manually. In your case
abstractList.add(Object1 as AbstractObject)
Remove out from the declaration of recyclerViewArray and it should work (I just tried it and it ran fine). e.g. I could run this line of code:
recyclerViewArray.add(HeaderItem("test"))
Note that when you remove out you still need to keep the fact that it's an ArrayList of ListItem objects. So you should declare it as:
var recyclerViewArray = arrayListOf<ListItem>()
Some of your code didn't quite compile for me, like having a property called object (I had to put backticks around that) and not putting the override modifier on the type property on HeaderItem.

DynamoDBMapper load cannot instantiate Kotlin data class

Using DynamoDBMapper within an AWS Lambda (i.e. not Android) written in Kotlin, I can save a record using a data class. However when I attempt to load a record to a data class, I receive a "DynamoDBMappingException: could not instantiate class" exception.
#DynamoDBTable(tableName = "Test")
data class TestItem(
#DynamoDBHashKey(attributeName="someKey")
#DynamoDBAttribute(attributeName = "someKey")
var someKey: String?,
#DynamoDBAttribute(attributeName = "someValue")
var someValue: String?
}
val ddbMapper = DynamoDBMapper(AmazonDynamoDBClientBuilder.defaultClient())
ddbMapper.load(TestItem::class.java, "xyz")
Results in the following exception:
com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException:
could not instantiate class
com.intuit.connect_to_pro.lambda_common_core.aws_service.TestItem
With the root exception being:
java.lang.NoSuchMethodException:
com.intuit.connect_to_pro.lambda_common_core.aws_service.TestItem.()
AWS has an example for Android that uses com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.DynamoDBMapper instead of com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper. I tried the Android version, but the result was the same.
https://docs.aws.amazon.com/aws-mobile/latest/developerguide/add-aws-mobile-nosql-database.html
Any help would be appreciated.
The DynamoDBMapper expects a class with an empty constructor. Using a Kotlin data class, you can specify default values for all parameters and use #JvmOverload, which will generate the empty constructor for JVM (Java). Also all parameters need to be mutable, so you need to use "var" instead of "val".
#DynamoDBTable(tableName = "Test")
data class TestItem #JvmOverloads constructor(
#DynamoDBHashKey(attributeName="someKey")
var someKey: String = "",
var someValue: String = ""
)
Make sure that all your classes have an empty constructor. In my case I had nested documents. Those had to have empty constructors too.
In Kotlin, an empty (parameterless) constructor will be created if you specify default values for all the attributes.
Also, make sure that the data from the db can be converted to the data in your classes.
For example, mine failed because I had an Integer property in my class while in the db I had a String. i.e. I had the String value "30" in the db, instead of the Integer value 30.

Class declarations in Kotlin

I was creating a sample Android project using Kotlin programming language using this blog. I'm new to Kotlin programming. I came across this line,
data class Cats(var data: Data? = null)
which I believe that it is, creating a class named Cats that has a variable named data. What does this data: Data? = null means? My whole class model is:
data class Cats(var data: Data? = null)
data class Data(var images: ArrayList<Image>? = null)
data class Image(var url: String? = "", var id: String? = "", var source_url: String? = "")
You are right that Cats class will have a mutable property named data, since it is declared inside a primary constructor of a class with var keyword (see the docs pages about classes and properties).
Next, question mark at type name in Kotlin means that a variable has nullable type, that is, it can store null value. Variables with not-null types, on the other hand, cannot hold nulls in Kotlin.
data: Data? = null is syntax for default parameter value. It allows not to pass data parameter to the constructor invocation, and in this case default value null will be used. This also works for functions.
And finally, data modifier at class declaration means that equals, hashCode, toString, copy and destructuring will be generated for the class, based on the properties declared in primary constructor.
=> Classes in Kotlin are declared using the keyword class:
class Invoice { }
=> Both the header and the body are optional; if the class has no body, curly braces can be omitted.
class Invoice