I am trying to load a global variable in kotlin directly from the application.yml:
telegram:
token: foo
to achieve this, in my class I've tried this:
#Value("\${telegram.token}")
val botToken: String
But it is throwing an error saying that I need to initialize the property. (For example, this doesn't throw an error but it is not my expected behaviour):
#Value("\${telegram.token}")
val botToken: String = ""
What I want is to inject the config value (foo) into this constant (botToken).
Either add it as a parameter in the constructor of the bean that contains the property:
class WhateverSpringManagedBeanClass(
#Value("\${telegram.token}") private val botToken: String
)
Or try the following (this makes botToken mutable):
#Value("\${telegram.token}")
lateinit var botToken: String
first of all it seems like you could use #Property(name = "telegram.token")
and then i would attempt
#Property(name = "telegram.token")
lateinit var token: String
private set
Related
I am trying to create a hashmap of a generic type to an array list type from FX Collections.
private val items = FXCollections.observableArrayList<T>()
private val itemsData = hashMapOf<T, FXCollections.observableArrayList<ItemData<T>>>()
The first line works fine, the second gives me a red line under 'observableArrayList'.
Unresolved reference: observableArrayList
This also works fine:
private val itemsData = hashMapOf<T, ItemData<T>>()
I'm new to kotlin and javafx, but even if importing observableArrayList directly doesn't help..
You're confusing a type with an object.
FXCollections.observableArrayList is a method that returns an instance of type ObservableList<E>. The declaration of the HashMap needs a type in the generics though.
Give this a try:
val itemsData = hashMapOf<T, ObservableList<ItemData<T>>>();
A simpler example as an explaination:
// delcare that my password storage has a string type as key and a string type as value
val myPasswords = hashMapOf<String, String>();
// add a pair of string instances
myPasswords["stackoverflow.com"] = "topsecret"
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")
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.
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.
When trying to define a setter that accepts a parameter type that can be used to construct a property, thusly:
class Buffer(buf: String) {}
class Foo {
var buffer: Buffer? = null
set(value: String) {
field = Buffer(value)
}
}
I get the error message:
Setter parameter type must be equal to the type of the property
So what's meant to be the Kotlin way of doing this?
As of Kotlin 1.1 it is not possible to overload property setters. The feature request is tracked here:
https://youtrack.jetbrains.com/issue/KT-4075
Currently, you would have to define a buffer extension function on String:
val String.buffer : Buffer
get() = Buffer(this)
and set the value with
Foo().buffer = "123".buffer