Kotlin - assign value inside while to use it outside - kotlin

I'm very new in kotlin and wanted to solve following problem with a do while:
I want to create a hash and want to check if there is the same hash stored in a key-value store as a key.
In java I would make it with a String variable which I declared outside the while. But that will only work with a var in Kotlin and I learned that it is common practise to avoid var.
My code looks as following (with var...)
var hash = ""
do {
hash = createHash(longUrl)
val optional = shortUrlRepository.findById(hash)
} while(optional.isPresent)
What would you say is the best way to solve this?
thank you a lot!

Maybe something like this?
val hash = generateSequence { createHash(longUrl) }
.first { !shortUrlRepository.findById(it).isPresent }
... and of course, you can always localize var and pass it outside as val.
val someVal = run {
var someVar: String = ""
// do super logic with var
someVar
}
...

Related

Can I observe the change fo a variable in Kotlin?

I know I can use get a notification when the value of a variable has changed, Code A is OK.
I hope to monitor the change of a normal variable such as var myFilename="OK" in Code B, but myObserv isn't launching when myFilename has changed.
Can I observe the change fo a variable in Kotlin?
Code A
var savedFilename: String by Delegates.observable("") {
prop, old, new -> ...
}
Code B
var myFilename="OK"
var myObserv String by Delegates.observable(myFilename) {
prop, old, new -> ...
}

Micronaut declarative client with base url per environment

I'd like to be able to use Micronaut's declarative client to hit an a different endpoint based on whether I'm in a local development environment vs a production environment.
I'm setting my client's base uri in application.dev.yml:
myserviceclient:
baseUri: http://localhost:1080/endpoint
Reading the docs from Micronaut, they have the developer jumping through quite a few hoops to get a dynamic value piped into the actual client. They're actually quite confusing. So I've created a configuration like this:
#ConfigurationProperties(PREFIX)
class MyServiceClientConfig {
companion object {
const val PREFIX = "myserviceclient"
const val BASE_URL = "http://localhost:1080/endpoint"
}
var baseUri: String? = null
fun toMap(): MutableMap<String, Any> {
val m = HashMap<String, Any>()
if (baseUri != null) {
m["baseUri"] = baseUri!!
}
return m
}
}
But as you can see, that's not actually reading any values from application.yml, it's simply setting a const value as a static on the class. I'd like that BASE_URL value to be dynamic based on which environment I'm in.
To use this class, I've created a declarative client like this:
#Client(MyServiceClientConfig.BASE_URL)
interface MyServiceClient {
#Post("/user/kfc")
#Produces("application/json")
fun sendUserKfc(transactionDto: TransactionDto)
}
The docs show an example where they're interpolating values from the config map that's built like this:
#Get("/api/\${bintray.apiversion}/repos/\${bintray.organization}/\${bintray.repository}/packages")
But how would I make this work in the #Client() annotation?
Nowhere in that example do they show how bintray is getting defined/injected/etc. This appears to be the same syntax that's used with the #Value() annotation. I've tried using that as well, but every value I try to use ends up being null.
This is very frustrating, but I'm sure I'm missing a key piece that will make this all work.
I'm setting my client's base uri in application.dev.yml
You probably want application-dev.yml.
But how would I make this work in the #Client() annotation?
You can put a config key in the #Client value using something like #Client("${myserviceclient.baseUri}").
If you want the url somewhere in your code use this:
#Value("${micronaut.http.services.occupancy.urls}")
private String occupancyUrl;

Better Kotlin way of getting roles from JWT Claims

I have the following code, that gets user roles from a io.jsonwebtoken.Claims object
val claims = jwtUtil.getAllClaimsFromToken(authToken)
val rolesMap = claims.get("role", ArrayList::class.java)
val roles = ArrayList<Role>()
for (rolemap in rolesMap) {
roles.add(Role.valueOf((rolemap as LinkedHashMap<String, String>)["authority"] as String))
}
Is there a better/cleaner way to get the role(s) as String in Kotlin?
You could do it like this. The main difference being the use of the higher order function map, which iterates a collection applying a function to create a new collection of the same size but of a new type.
Also, unless you need the intermidiate parts of the function to be assigned to variables for debugging/logging purposes then you can simply ommit assigning values and just chain function calls, but it can make it less easy to read (debatable):
return jwtUtil.getAllClaimsFromToken(authToken)
.get("role", ArrayList::class.java)
.map {
Role.valueOf((it as Map<String, String>)["authority"])
}

how to add Array index value in Kotlin?

first, I create empty Array(Kotlin) instance in companion object.
companion object {
var strarray: Array<String> = arrayOf()
var objectarray: LinkedHashMap<Int, List<Any>> = LinkedHashMap<Int, List<Any>>()
}
and I expected that I use empty array instance when read textString from CSV File.
fun csvFileToString():String {
val inputStream = File(Paths.get("").toAbsolutePath().toString()
.plus("/src/main/SampleCSVFile_2kb.csv")).inputStream()
val reader = inputStream.bufferedReader()
var iterator = reader.lineSequence().iterator()
var index:Int = 1;
while (iterator.hasNext()){
var lineText:String = iterator.next()
strarray.set(index, lineText)
index++
}
return ""
}
but when I run that source code
a.csvFileToString()
println(CsvParser.strarray)
occured exception
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
strarray.set(index, lineText) <<<<<<<<< because of this line
can I use Array(from kotlin collection) like ArrayList(from java collection)?
You can add a new item to an array using +=, for example: item += item
private var songs: Array<String> = arrayOf()
fun add(input: String) {
songs += input
}
Size of Array is defined at its creation and cannot be modified - in your example it equals 0.
If you want to create Array with dynamic size you should use ArrayList.
arrayOf gives you an array. Arrays have fixed length even in Java.
listOf gives you an immutable list. You cannot add or remove items in this list.
What you're looking for is mutableListOf<String>.
In your current approach, reusing a member property, don't forget to clear the list before every use.
Your code can be further simplified (and improved) like so:
out.clear()
inputStream.bufferedReader().use { reader -> // Use takes care of closing reader.
val lines = reader.lineSequence()
out.addAll(lines) // MutableList can add all from sequence.
}
Now imagine you wanted to consume the output list but needed to parse another file at the same time.
Consider working towards a pure function (no side effects, for now no accessing member properties) and simplifying it even further:
fun csvFileToString(): String { // Now method returns something useful.
val inputStream = File(Paths.get("").toAbsolutePath().toString()
.plus("/src/main/SampleCSVFile_2kb.csv")).inputStream()
inputStream.bufferedReader().use {
return it.lineSequence().joinToString("\n")
}
}
In this case we can totally skip the lists and arrays and just read the text:
inputStream.bufferedReader().use {
return it.readText()
}
I'm assuming that's what you wanted in the first place.
Kotlin has a lot of useful extension functions built-in. Look for them first.

toString returning all of an objects getter methods

I'm using ColdFusion, but I'd be interested to know how other languages cope with this.
Is there a better way of returning all of an objects variables (getters) without writing a massive toString() method on the object.
variables.oCity = createObject("component", "_lbr._core._locations.city").init();
variables.oCity.setName(request.parameters.sCityName);
variables.oCity.setCountryID(request.parameters.nLocationCountryID);
if(request.parameters.nStateID eq 0){
variables.stArgs = {};
variables.stArgs.sState = request.parameters.sLocationCountry;
variables.stArgs.nCheckCountryID = request.parameters.nCountryID;
variables.oCity.setStateID = application.stObj.oLocationBusiness.getState(argumentCollection=variables.stArgs).getStateID();
} else {
variables.oCity.setStateID = request.parameters.nStateID;
}
My code looks like that. What I'd like is to output everything I have just set (as well as anything that the object defaults too) without writing a giant toString that concatenates all the various variables that might look like this:
Object: StateID = 12, Name = "Argentina", CountryID = 32, CityID = 44
My heart tells me this is unlikely.
This depends on how you are storing your variables within your object. I generally store all of my variables in a variables.instance structure. I then create a get() that simply returns the variables.instance structure:
public struct function get(){
return Duplicate(variables.instance);
}
If you use cfproperty, and accessor=true or persistent=true in CF9+, a dump of the cfc will return all the properties without getter=false.