Chronicle Values: getter that returns Array instead of individual items - chronicle

So, I have a Value Interface with these array field getter and setter methods, which works
interface Instrument: Marshallable {
...
fun setBidAt(index: Int, entry: OrderBookEntry)
#Array(length = 10)
fun getBidAt(index: Int): OrderBookEntry
}
interface OrderBookEntry: Marshallable{
var level: Int
var quantity: Long
var price: Double
var orders: Long
var side: OrderBookSide
}
However, I want a getter and setter that interact with the whole Array, something like:
interface Instrument: Marshallable {
...
fun setBids(entries: kotlin.Array<OrderBookEntry>)
#Array(length = 20)
fun getBids(): kotlin.Array<OrderBookEntry>
}
but as expected encountered some exceptions:
java.lang.IllegalStateException: bids field type class [Lme.oms.instrument.OrderBookEntry; is not supported: not a primitive, enum, CharSequence or another value interface
Now, does this mean that I can't leverage Chronicle Value Interface and have to create a custom class to achieve this? I have tried to look in both ChronicleValues and ChronicleMap test cases, seems like there is no test for this scenario?
EDIT: I managed to find a workaround by leveraging kotlin's extension function:
fun Instrument.getAsks(): kotlin.Array<OrderBookEntry>{
val array = arrayOf<OrderBookEntry>()
for (i in (0 until OrderBookMaxSize)) {
array[i] = getAskAt(i)
}
return array
}

If you use an interface via the values module, the elements of the array also need to be values so they can be flyweights as well. Without this information, it can't determine how large the elements of the array will be.

Related

Kotlin: Specify input-constraints in interface

Lets say I have the following interface:
interface MathThing {
fun mathFunction(x : Int)
}
Let's say the constraint I want to put onto this function is that x cannot be negative.
How can I make sure that every time this (or any other arbitrary) condition isn't met on a object of type MathThing, a (custom) exception is thrown?
One way is to use a wrapper class for your function parameters. You can make an extension function so it's a little easier to pass values to the function.
data class NonNegative(val value: Int) {
init{ if (value < 0) throw IllegalArgumentException("Input must not be negative.") }
}
fun Int.nonNegative() = NonNegative(this)
interface MathThing {
fun mathFunction(x : NonNegative)
}

Polymorphic #RequestBody in Spring-Boot

The problem's pretty straightforward. I have a couple of events that derive from the same interface, and I'd like to deserialize them to their propper super-class.
I know how to do that with an object mapper, but using my own mapper would mean letting Spring-Boot parse the #RequestBody as a String and then doing it myself, which isn't the worlds end, but I can't help but suspect that Spring provides proper tools to handle this kind of situation. Trouble is, I can't seem to find them.
Here's a bit of sample code:
example event:
interface YellowOpsEvent {
val user: String
val partner: String
val subject: String
val change: NatureOfChange
}
data class StatusChangedEvent(override val user: String,
override val partner: String,
override val subject: String,
val before: String,
val after: String): YellowOpsEvent {
override val change = NatureOfChange.Changed
}
controller:
#PostMapping("/event")
fun writeEvent(#RequestBody event: YellowOpsEvent) { // < I expect this not to throw an exception
val bugme = event is StatusChangedEvent // < I expect this to return true if I send the proper event data.
}
Just to clarify, I perfectly understand why this doesn't work out of the box. The trouble is, I can't find out what I need to do to make it work.
The link in pL4Gu33's comment lead me in the right direction, but it took some additional searching and fiddling, plucking information from here and there to arrive at the solution that would finally work, so I'm summarising it here for completeness.
The trouble is that you'll need two annotations, one on the interface and one on the implementing classes, the combined use of which seems somewhat ill-documented.
First, on the interface, add this annotation. Contrary to some tutorials you will find, no further annotation of the interface is required:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
interface YellowOpsEvent {
val user: String
val partner: String
val subject: String
val change: NatureOfChange
}
According to some documentation, this alone should be enough for propper deserialisation. The spring-boot controller, however, will throw an exception because the passed root name does not match the class it was expecting.
// the above will throw an exception when the serialization product is sent to this controller:
#PostMapping("/event")
fun writeEvent(#RequestBody event: YellowOpsEvent) { // < I expect this not to throw an exception
val bugme = event is StatusChangedEvent // < I expect this to return true if I send the proper event data.
}
To fix that, add the #JsonRootName annotation to any implementing classes, with the interface's name. Most documentation of this annotation don't use it for this, instead just for renaming the type, and even when it's mentioned in the linked question in the context of polymorphism, it wrongly uses its own name. This is what it needs to look like:
#JsonRootName("YellowOpsEvent")
data class StatusChangedEvent(override val user: String,
override val partner: String,
override val subject: String,
val before: String,
val after: String): YellowOpsEvent {
override val change = NatureOfChange.Changed
}
Now it works! :)

How can I create Hashmap<String,Int : String,String : String,String> in Kotlin for sorting

I know this character (:) is meaningless in my statement, but I wanted to explain what I want. I want to sort a lot of hashmaps adding Arraylist and using sortedBy but I cant because my values return strings.
Here is my code:
newReference.addValueEventListener(object : ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
chatMessages.clear()
for(ds in p0.child(playerIDmatchWhoIs).children){
var hashMap = ds.getValue() as HashMap<String, String>
var datetime = hashMap.get("datetime").toString()
var usermail = hashMap.get("usermail")
var usermessage = hashMap.get("usermessage")
chatMessages.add("${usermail}: ${usermessage}")
recyclerViewAdapter.notifyDataSetChanged()
}
}
})
(I want to sort this hashMap, it has datetime value but is returning string.)
println(hashMap): I/System.out: {datetime=1574807563747, usermessage=jmjgmhg, usermail=1#gmail.com}
I assume that chatMessages is of type List<String>. This is generally bad because you cannot to anything with strings. I would suggest you to create a data class which contains all information about a chat message, like so:
data class ChatMessage(val dateTime: Int, val userMail: String?, val userMessage: String?) : Comparable<ChatMessage> {
override fun compareTo(other: ChatMessage) = this.dateTime.compareTo(other.dateTime)
}
As you can see, this class implements the Comparable<ChatMessage> interface. If you then define the chatMessages list like so
private val chatMessages = mutableListOf<ChatMessage>()
you can call chatMessages.sort() which will then sort the list according to dateTime (see the implementation of compareTo in ChatMessage). The final code would look like that:
data class ChatMessage(val dateTime:Int?, val userMail: String?, val userMessage: String?) : Comparable<ChatMessage> {
override fun compareTo(other: ChatMessage) = this.dateTime.compareTo(other.dateTime)
}
private val chatMessages = mutableListOf<ChatMessage>()
fun yourCode() {
newReference.addValueEventListener(object : ValueEventListener {
/* Use proper variable naming. Nobody will understand, what p0 is, but if you name
it dataSnapshot, everyone knows at a glance. */
override fun onDataChange(dataSnapshot: DataSnapshot) {
chatMessages.clear()
// Again, what is ds exactly? Name it properly.
for (ds in dataSnapshot.child(playerIDmatchWhoIs).children) {
// Kotlin recommends to use val instead of var.
// This way, you know that your variables cannot be modified unless you want them to be modified.
val hashMap = ds.getValue() as HashMap<String, String>
// use indexing instead of the get() method
val dateTime = hashMap["datetime"]
val userMail = hashMap["usermail"]
val userMessage = hashMap["usermessage"]
// TODO: Handle null values properly
chatMessages.add(ChatMessage(dateTime!!.toInt(), userMail, userMessage))
recyclerViewAdapter.notifyDataSetChanged()
}
chatMessages.sort()
}
})
}
This assumes that you want to store your timestamp as an integer. However, I would rather recommend to use a time library like java.time (built into java). In that case, you can use java.time.Instant which has many more possibilities to handle time and all the difficulties to handle time.
Read more about java.time.Instant in the Android docs. If you want to learn how to parse a String to java.time.Instant, this might be interesting.

how to customized sorting in an enum class in kotlin

I do have a enum class in kotlin in which I have to sort them differently based on a input parameters.
As of now, I have this class defined
enum class ProductItem constructor(
val color,
val price,
val position
){
SHOES("red", "$", 2)
CAR("blue", "$$$$$", 1)
BOAT("green", "$$$$$$$$$$$$$", 3)
}
As of now using a simplify code like this:
it.sortedBy { it.ProductItem?.position })
I was expecting that the list of enum returned will be sorted in ascending order and show: CAR, SHOES and BOAT but it still shows SHOES, CAR, BOAT. It looks like the params position is not took into account. Any idea how to use the params position to sort the list of enum
Thanks
From the look of your code I suspect you have some class (e.g. Order) which has an optional property called ProductItem, which returns a ProductItem enum value. And you then have a list or array of these Order objects, which you want to sort by the position of the associated ProductItem. Is that correct?
If so, here's some code below which shows how the list of orders can be sorted...
enum class ProductItem constructor(
val color: String,
val price: String,
val position: Int
) {
SHOES("red", "$", 2),
CAR("blue", "$$$$$", 1),
BOAT("green", "$$$$$$$$$$$$$", 3)
}
data class Order(val ProductItem: ProductItem? = null)
val orders = listOf(Order(ProductItem.SHOES), Order(ProductItem.CAR), Order(ProductItem.BOAT))
val sortedOrders = orders.sortedBy { it.ProductItem?.position }
Does that give you what you want?

Returning object of type specified in method arguments instead of AnyRef

I have the following method:
#org.springframework.stereotype.Service
class EntityCacheManager {
def get(cacheId: String, entityClass: Class[_]): AnyRef = { ... }
//...
}
So to use it, i have to write this:
val cachedEntity = entityCacheManager.get(cacheId, classOf[SomeEntity]).asInstanceOf[SomeEntity]
Is there some way to make EntityCacheManager.get() returning instance of type entityClass which is specified in method params? I'd like to avoid casting asInstanceOf every time i use this method. I know it would be nice to use generic definition of type EntityCacheManager, but it's also a spring-managed bean, so i think using generics will cause troubles.
You can use a more idiomatic scala approach by using the ClassTag typeclass
class EntityCacheManager {
def get[T: ClassTag](cacheId: String): T = {
val entityClass = implicitly[ClassTag[T]].runtimeClass
val myObject: T = ??? // you retrieve your object somehow using entityClass
myObject
}
}
you can now use it like this:
val myEntityClassInstance = get[MyEntityClass]("key")

Resources