Retrieve Item from realm sort by id - kotlin

I've a realm class A in my android project -
open class A(
var id: Int? = null,
var level: String? = null,
var state: String? = null,
var updated_at: String? = null,
var created_at: String? = null,
var person: Person? = null
): RealmObject()
and Person -
open class Person(
var id: Int? = null,
var name: String? = null,
var email: String? = null,
var url: String? = null
): RealmObject()
I can retrieve list of items of class A sorted by Class A's id attribute -
fun getItemsOfA() : List<A> {
val listToBeReturn: MutableList<A> = mutableListOf()
DBManager.getRealm().executeTransection { realm ->
val tempList = realm.where(A::class.java).sort("id").findAll()
for (item in tempList) {
listToBeReturn.add(item)
}
And I'm getting sorted list. But I want to have a sorted list by the Person's id attribute instead of A's id. Any insight on this.
How can I achieve these?
Thanks & Regards

Related

Micronaut Data JDBC Nested Entities

I have been investigating using Micronaut Data JDBC as an augmentation for existing jdbi queries. Is it possible to do nested MappedEntity's and return the children?
Example is for a simple Warehouse Management System with a relation:
company
+- warehouse
+- inventory
What I'm wanting to be able to do is query up from the inventory table and get the parent of warehouse and grandparent of company. It is a one-to-many relationship with a company able to have multiple warehouses and a warehouse able to have multiple pieces of inventory.
My Entities look like
The example project I've been playing with is at wms-api
#JdbcRepository
interface CompanyRepository : PageableRepository<Company, UUID>
#MappedEntity
data class Company(
#field:Id
#field:GeneratedValue
var id: UUID? = null,
#field:GeneratedValue
var timeCreated: OffsetDateTime? = null,
#field:GeneratedValue
var timeUpdated: OffsetDateTime? = null,
var name: String
)
#JdbcRepository
interface WarehouseRepository : GenericRepository<Warehouse, UUID> { // used GenericRepository to allow the mapping of Company
#Join(value = "company")
fun findById(id: UUID): Warehouse?
#Join(value = "company")
fun findByCompany(company: Company, pageable: Pageable): Slice<Warehouse>
#Join(value = "company")
fun findAllByCompany(company: Company, pageable: Pageable): Slice<Warehouse>
#Join(value = "company")
fun existsByLocationAndCompany(location: String, company: Company): Boolean
fun save(warehouse: Warehouse): Warehouse
fun update(warehouse: Warehouse): Warehouse
}
#MappedEntity
data class Warehouse(
#field:Id #field:GeneratedValue
var id: UUID? = null,
#field:GeneratedValue
var timeCreated: OffsetDateTime? = null,
#field:GeneratedValue
var timeUpdated: OffsetDateTime? = null,
var location: String,
#field:Relation(value = MANY_TO_ONE)
var company: Company
)
#JdbcRepository
interface InventoryRepository : GenericRepository<Inventory, UUID> {
fun save(inventory: Inventory): Inventory
#Join(value = "warehouse")
// FIXME need some way to tell repo to also pull company which is attached to warehouse
fun findById(id: UUID): Inventory?
}
#MappedEntity
data class Inventory(
#field:Id
#field:GeneratedValue
var id: UUID? = null,
#field:GeneratedValue
var timeCreated: OffsetDateTime? = null,
#field:GeneratedValue
var timeUpdated: OffsetDateTime? = null,
var manufacturer: String,
var barcode: String,
var name: String,
#field:Relation(value = MANY_TO_ONE) // FIXME the problem is caused by this.
var warehouse: Warehouse,
)
Relevant part of the stacktrace
Caused by: io.micronaut.core.reflect.exception.InstantiationException: Null argument specified for [company]. If this argument is allowed to be null annotate it with #Nullable
at io.micronaut.core.beans.AbstractBeanIntrospection.instantiate(AbstractBeanIntrospection.java:121)
at io.micronaut.core.beans.BeanIntrospection.instantiate(BeanIntrospection.java:81)
at io.micronaut.data.runtime.mapper.sql.SqlResultEntityTypeMapper.readEntity(SqlResultEntityTypeMapper.java:345)
I would like to not have to make the Warehouse.company property optional if possible.
In the linked project there is a docker-compose.yml under support that can be used to fire up Postgres and then run the test suite, and the problem should pop up as a failure.
Thanks!
Figured it out. Had to change the InventoryRepository's findById method to look like
#JoinSpecifications(
Join(value = "warehouse"),
Join(value = "warehouse.company")
)
fun findById(id: UUID): Inventory?

Gson child object attributes return null

Im trying to map a json to a data class in kotlin
JSON :
{
"TimeZones": [
{
"MapZone": {
"Other": "Afghanistan Standard Time",
"Type": "Asia/Kabul",
"Territory": "001"
}
}
]
}
my data TimeZones.kt class
data class TimeZones (
#Expose var TimeZones: List<MapZone>? = null
)
data class MapZone (
#Expose var Other: String? = null,
#Expose var Type: String? = null,
#Expose var Territory: String? = null
)
but when I run this code the mapzone attribute values are always null
Gson().fromJson(Utils.readJSONFroRaw(), TimeZones::class.java)
I want to map this properly
You are missing one level of the structure:
data class TimeZones (
#Expose var TimeZones: List<TimeZone>? = null
)
data class TimeZone (
#Expose var MapZone: MapZone? = null
)
data class MapZone (
#Expose var Other: String? = null,
#Expose var Type: String? = null,
#Expose var Territory: String? = null
)

How to define a no-argument constructor in Kotlin file with #Parcelize annotation [duplicate]

I have 10+ variables declared in Kotlin data class, and I would like to create an empty constructor for it like how we typically do in Java.
Data class:
data class Activity(
var updated_on: String,
var tags: List<String>,
var description: String,
var user_id: List<Int>,
var status_id: Int,
var title: String,
var created_at: String,
var data: HashMap<*, *>,
var id: Int,
var counts: LinkedTreeMap<*, *>,
)
Expected usage:
val activity = Activity();
activity.title = "New Computer"
sendToServer(activity)
But the data class requires all arguments to be passed while creating a constructor. How can we simplify this like the Java POJO class constructor?
val activity = Activity(null,null,null,null,null,"New Computer",null,null,null,null)
sendToServer(activity)
You have 2 options here:
Assign a default value to each primary constructor parameter:
data class Activity(
var updated_on: String = "",
var tags: List<String> = emptyList(),
var description: String = "",
var user_id: List<Int> = emptyList(),
var status_id: Int = -1,
var title: String = "",
var created_at: String = "",
var data: HashMap<*, *> = hashMapOf<Any, Any>(),
var id: Int = -1,
var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
)
Declare a secondary constructor that has no parameters:
data class Activity(
var updated_on: String,
var tags: List<String>,
var description: String,
var user_id: List<Int>,
var status_id: Int,
var title: String,
var created_at: String,
var data: HashMap<*, *>,
var id: Int,
var counts: LinkedTreeMap<*, *>
) {
constructor() : this("", emptyList(),
"", emptyList(), -1,
"", "", hashMapOf<Any, Any>(),
-1, LinkedTreeMap<Any, Any>()
)
}
If you don't rely on copy or equals of the Activity class or don't use the autogenerated data class methods at all you could use regular class like so:
class ActivityDto {
var updated_on: String = "",
var tags: List<String> = emptyList(),
var description: String = "",
var user_id: List<Int> = emptyList(),
var status_id: Int = -1,
var title: String = "",
var created_at: String = "",
var data: HashMap<*, *> = hashMapOf<Any, Any>(),
var id: Int = -1,
var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
}
Not every DTO needs to be a data class and vice versa. In fact in my experience I find data classes to be particularly useful in areas that involve some complex business logic.
If you give default values to all the fields - empty constructor is generated automatically by Kotlin.
data class User(var id: Long = -1,
var uniqueIdentifier: String? = null)
and you can simply call:
val user = User()
the modern answer for this should be using Kotlin's no-arg compiler plugin which creates a non argument construct code for classic apies more about here
simply you have to add the plugin class path in build.gradle project level
dependencies {
....
classpath "org.jetbrains.kotlin:kotlin-noarg:1.4.10"
....
}
then configure your annotation to generate the no-arg constructor
apply plugin: "kotlin-noarg"
noArg {
annotation("your.path.to.annotaion.NoArg")
invokeInitializers = true
}
then define your annotation file NoArg.kt
#Target(AnnotationTarget.CLASS)
#Retention(AnnotationRetention.SOURCE)
annotation class NoArg
finally in any data class you can simply use your own annotation
#NoArg
data class SomeClass( val datafield:Type , ... )
I used to create my own no-arg constructor as the accepted answer , which i got by search but then this plugin released or something and I found it way cleaner .
Along with #miensol answer, let me add some details:
If you want a Java-visible empty constructor using data classes, you need to define it explicitely.
Using default values + constructor specifier is quite easy:
data class Activity(
var updated_on: String = "",
var tags: List<String> = emptyList(),
var description: String = "",
var user_id: List<Int> = emptyList(),
var status_id: Int = -1,
var title: String = "",
var created_at: String = "",
var data: HashMap<*, *> = hashMapOf<Any, Any>(),
var id: Int = -1,
var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
) {
constructor() : this(title = "") // this constructor is an explicit
// "empty" constructor, as seen by Java.
}
This means that with this trick you can now serialize/deserialize this object with the standard Java serializers (Jackson, Gson etc).
If you give a default value to each primary constructor parameter:
data class Item(var id: String = "",
var title: String = "",
var condition: String = "",
var price: String = "",
var categoryId: String = "",
var make: String = "",
var model: String = "",
var year: String = "",
var bodyStyle: String = "",
var detail: String = "",
var latitude: Double = 0.0,
var longitude: Double = 0.0,
var listImages: List<String> = emptyList(),
var idSeller: String = "")
and from the class where the instances you can call it without arguments or with the arguments that you have that moment
var newItem = Item()
var newItem2 = Item(title = "exampleTitle",
condition = "exampleCondition",
price = "examplePrice",
categoryId = "exampleCategoryId")
Non-empty secondary constructor for data class in Kotlin:
data class ChemicalElement(var name: String,
var symbol: String,
var atomicNumber: Int,
var atomicWeight: Double,
var nobleMetal: Boolean?) {
constructor(): this("Silver", "Ag", 47, 107.8682, true)
}
fun main() {
var chemicalElement = ChemicalElement()
println("RESULT: ${chemicalElement.symbol} means ${chemicalElement.name}")
println(chemicalElement)
}
// RESULT: Ag means Silver
// ChemicalElement(name=Silver, symbol=Ag, atomicNumber=47,
// atomicWeight=107.8682, nobleMetal=true)
Empty secondary constructor for data class in Kotlin:
data class ChemicalElement(var name: String,
var symbol: String,
var atomicNumber: Int,
var atomicWeight: Double,
var nobleMetal: Boolean?) {
constructor(): this("", "", -1, 0.0, null)
}
fun main() {
var chemicalElement = ChemicalElement()
println(chemicalElement)
}
// ChemicalElement(name=, symbol=, atomicNumber=-1,
// atomicWeight=0.0, nobleMetal=null)
From the documentation
NOTE: On the JVM, if all of the parameters of the primary constructor
have default values, the compiler will generate an additional
parameterless constructor which will use the default values. This
makes it easier to use Kotlin with libraries such as Jackson or JPA
that create class instances through parameterless constructors.
I'd suggest to modify the primary constructor and add a default value to each parameter:
data class Activity(
var updated_on: String = "",
var tags: List<String> = emptyList(),
var description: String = "",
var user_id: List<Int> = emptyList(),
var status_id: Int = -1,
var title: String = "",
var created_at: String = "",
var data: HashMap<*, *> = hashMapOf<Any, Any>(),
var id: Int = -1,
var counts: LinkedTreeMap<*, *> = LinkedTreeMap<Any, Any>()
)
You can also make values nullable by adding ? and then you can assing null:
data class Activity(
var updated_on: String? = null,
var tags: List<String>? = null,
var description: String? = null,
var user_id: List<Int>? = null,
var status_id: Int? = null,
var title: String? = null,
var created_at: String? = null,
var data: HashMap<*, *>? = null,
var id: Int? = null,
var counts: LinkedTreeMap<*, *>? = null
)
In general, it is a good practice to avoid nullable objects - write the code in the way that we don't need to use them. Non-nullable objects are one of the advantages of Kotlin compared to Java. Therefore, the first option above is preferable.
Both options will give you the desired result:
val activity = Activity()
activity.title = "New Computer"
sendToServer(activity)

How to find the updated fields between a payload and an entity fetched from DB and create an object having fields with updated values and rest Null

Given an update request for a record in DB, I have to find a difference between the payload and existing data in DB then create a new Object which has updated fields with Payload values and rest as Null.
I have created a function which gives me a list of field names which were updated, But I'm unable to create a new object which has values for only these updated fields.The problem is that the function uses "field: Field in cpayload.javaClass.declaredFields" which is kind of generic so I'm unable to set these fields.
fun findupdatedFieldsList(cpayload: Customer, cEntity: Customer): List<String> {
// var customerToPublish = Customer()
val updatedFieldsList: MutableList<String>
updatedFieldsList = ArrayList()
for (field: Field in cpayload.javaClass.declaredFields) {
field.isAccessible = true
val value1 = field.get(cpayload).toString()
val value2 = field.get(cEntity).toString()
!Objects.equals(value1, value2).apply {
if (this) {
// customerToPublish.birthDate=field.get(cpayload).toString()
updatedFieldsList.add(field.name)
}
}
}
return updatedFieldsList
}
#Entity
#Table
data class Customer(
#Id
val partyKey: UUID,
var preferredName: String?,
var givenName: String?,
var lastName: String?,
var middleName: String?,
var emailAddress: String,
var mobileNumber: String,
val birthDate: String?,
val loginOnRegister: Boolean,
var gender: Gender?,
var placeOfBirth: String?,
var createdDate: LocalDateTime = LocalDateTime.now(),
var updatedDate: LocalDateTime = LocalDateTime.now()
)
Desired Output
val customer = Customer(
preferredName = Updated name,
partyKey = partyKey.value,
givenName = Updated name,
lastName = null,
middleName = null,
emailAddress = Updated email,
mobileNumber = null,
birthDate = null,
gender = null,
placeOfBirth = null
)
I was able to construct a solution using Kotlin's reflect. It is generic and can be applied to any Kotlin class that have primary constructor. Unfortunately it won't work with Java classes
You would need to add kotlin-reflect package to your build tool config, e.g. for Gradle:
implementation 'org.jetbrains.kotlin:kotlin-reflect:XXXXXX'
First we will build a function to extract updated properties. Please take a note that we also need to extract properties that are mandatory (non-nullable and without default). We add them to a map of propertyName -> propertyValue:
fun Map<String?, KParameter>.isOptional(name: String) = this[name]?.isOptional ?: false
fun <T : Any> findUpdatedProperties(payload: T, entity: T): Map<String, Any?> {
val ctorParams = payload::class.primaryConstructor!!.parameters.associateBy { it.name }
return payload::class.memberProperties.map { property ->
val payloadValue = property.call(payload)
val entityValue = property.call(entity)
if (!Objects.equals(payloadValue, entityValue) || (!ctorParams.isOptional(property.name))) {
property.name to payloadValue
} else {
null
}
}
.filterNotNull()
.toMap()
}
Then we call this function and construct a new instance of provided class:
fun <T : Any> constructCustomerDiff(clazz: KClass<T>, payload: T, entity: T): T {
val ctor = clazz.primaryConstructor!!
val params = ctor.parameters
val updatedProperties = findUpdatedProperties(payload, entity)
val values = params.map { it to updatedProperties[it.name] }.toMap()
return ctor.callBy(values)
}
Take a note that missing primary constructor will throw NullPointerException because of use of !!.
We could call this funcion as constructCustomerDiff(Customer::class, payload, entity), but we can do better with reified types:
inline fun <reified T : Any> constructCustomerDiff(payload: T, entity: T): T {
return constructCustomerDiff(T::class, payload, entity)
}
Now we can use this function in convenient Kotlin style:
val id = UUID.randomUUID()
val payload = Customer(
partyKey = id,
preferredName = "newName",
givenName = "givenName"
)
val entity = Customer(
partyKey = id,
preferredName = "oldName",
givenName = "givenName" // this is the same as in payload
)
val x = constructCustomerDiff(payload, entity)
assert(x.partyKey == id && x.givenName == null || x.preferredName == "newName")

Kotlin create object with params syntax

I have an object
class Person {
#JsonProperty("name")
var name: String? = null
#JsonProperty("id")
lateinit var id: String}
There is an only empty constructor and I want to create a person so I wrote:
val person = Person()
person.name = "someName"
person.id = "SomeId"
I'm pretty sure that there is a prettier syntax, something like
val person = Person {name = "someName" , id = "someId"}
but I can't find an example.
am I missing something? should I create a secondary constructor to use this syntax or is there another way?
Please check apply method.
Your code will be like this:
val person = Person().apply {name = "someName", id = "someId"}
Another way - you can change declaration of Person to (e.g. just change brackets, replace var to val and remove lateinit):
class Person (#JsonProperty("name") val name: String? = null,
#JsonProperty("id") val id: String )
Then you will able to do this:
val person = Person(name = "someName", id = "someId")
You can achieve it with the constructor parameter.
class Person(
#JsonProperty("name")
var name: String? = null,
#JsonProperty("id")
var id: String
)
val person = Person(name = "someName", id = "someId")
Another way is make your class and desired variables open to be overridden.
open class Person {
#JsonProperty("name")
open var name: String? = null
#JsonProperty("id")
open var id: String = ""
}
val person = object : Person() {
override var name: String? = "SomeName"
override var id = "SomeId"
}