I'm creating an API rest and I need it when I do "find ALL" instead of fetching all the data, I just fetch a few. With Java I did it this way:
#GetMapping(value = "/pagina")
public ResponseEntity<Page<PersonFindDTO>> findAll(
#RequestParam(value = "page", defaultValue = "0") Integer page,
#RequestParam(value = "linesPerPage", defaultValue = "24") Integer linesPerPage,
#RequestParam(value = "order", defaultValue = "ASC") String order,
#RequestParam(value = "orderBy", defaultValue = "name") String orderBy) {
var person = personService.findAll(page, linesPerPage, order, orderBy);
var personFindDto = person.map(PersonFindDTO::new);
return ResponseEntity.ok().body(personFindDTO);
}
With Kotlin, I'm trying this way:
#GetMapping(value = ["/{companyId}/{active}"])
override fun findAll(
#RequestParam(value = "page", defaultValue = "0") page: Int,
#RequestParam(value = "linesPerPage", defaultValue = "24") linesPerPage: Int,
#RequestParam(value = "order", defaultValue = "ASC") order: String,
#RequestParam(value = "orderBy", defaultValue = "tradeName") orderBy: String,
#PathVariable companyId: Long, #PathVariable active: Boolean): ResponseEntity<Page<Any>> {
val lp = service.findAll(page, linesPerPage, order, orderBy, companyId, active)?.let {
it.map {
fun LegalPerson.toLegalPersonMPage() = LegalPersonMPage(id = it.id,
tradeName = it.tradeName, companyName = it.companyName, cnpj = it.cnpj)
}
}
return ResponseEntity.ok().body(lp)
}
But the return is always empty. Could anyone help? Please.
UPDATE:
My LegalPerson Class
data class LegalPerson(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
override var id: Long,
#Column(nullable = false)
val companyId: Long,
#Column(nullable = false)
var active: Boolean,
#Column(nullable = false, length = 100)
val tradeName: String,
#Column(nullable = false, length = 100)
val companyName: String,
#Column(nullable = false, length = 100)
val email: String,
#Column(nullable = false, length = 18)
val cnpj: String,
#Column(length = 15)
val stateRegistration: String,
#Column(length = 15)
val municipalRegistration: String,
#Column(nullable = false)
val openingDate: LocalDate,
#Column(nullable = false)
val address: Long,
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "phone", schema = "legal_person")
val phones: List<Long>
)
My LegalPersonMPage class
data class LegalPersonMPage(
val id: Long,
val tradeName: String,
val companyName: String,
val cnpj: String
) {
}
The function LegalPerson.toLegalPersonMPage() is defined but never called. To make this clearer define the function outside of map {...} and call it inside of map {...}.
fun LegalPerson.toLegalPersonMPage() = LegalPersonMPage(id = this.id,
tradeName = this.tradeName, companyName = this.companyName, cnpj = this.cnpj)
#GetMapping(value = ["/{companyId}/{active}"])
override fun findAll(
#RequestParam(value = "page", defaultValue = "0") page: Int,
#RequestParam(value = "linesPerPage", defaultValue = "24") linesPerPage: Int,
#RequestParam(value = "order", defaultValue = "ASC") order: String,
#RequestParam(value = "orderBy", defaultValue = "tradeName") orderBy: String,
#PathVariable companyId: Long, #PathVariable active: Boolean): ResponseEntity<Page<Any>> {
val lp = service.findAll(page, linesPerPage, order, orderBy, companyId, active)?.let {
it.map { legalPerson -> legalPerson.toLegalPersonMPage() }
}
return ResponseEntity.ok().body(lp)
}
Related
I have two tables like as I described below
object Categories : LongIdTable() {
val name = varchar(name = "name", length = 50).uniqueIndex()
val count = integer(name = "count")
val page = integer(name = "page")
}
object Images : LongIdTable() {
val color = varchar(name = "color", length = 100)
val blurHash = varchar(name = "blurHash", length = 200)
val unsplashId = varchar(name = "unsplashId", length = 200)
val category = reference(name = "category", Categories.name).nullable()
val isAvailable = bool(name = "isAvailable")
val imagePath = varchar(name = "imagePath", length = 500)
}
and here is my Image & Category data classes
#Serializable
data class Image(
val id: Long,
val unsplashId: String,
val isAvailable: Boolean = false,
val color: String,
val blurHash: String,
var category: Category?,
val imagePath: String,
)
#Serializable
data class Category(
val id: Long,
val name: String,
val count: Int,
var imagePath: String?,
val page: Int
)
when I want to find images by their id I can't map category attribute
fun getImageById(id: Long): Image {
val images = ArrayList<Image>()
var categoryName = ""
transaction {
Images.select {
Images.id eq id
}.map { row ->
categoryName = row[Images.category]!!
images.add(
Image(
id = row[Images.id].value,
unsplashId = row[Images.unsplashId],
isAvailable = false,
color = row[Images.color],
blurHash = row[Images.blurHash],
category = null,
imagePath = row[Images.imagePath]
)
)
}
images[0].category = categoryRepository.getCategoryByName(categoryName)
}
return images[0]
}
how can I solve this priblem?
I am trying to define a Kotlin sealed class which consists of a number of data classes. The latter are used to define data transfer objects (DTO) representing the mySQL tables in a room database. I introduced the sealed class to generalize the different DTOs and be able to refer to them all by their supertype (DTO - the common properties each specific DTO has, eg. "id", etc.).
This compiles alright, but I don't think Kotlin understands that the data classes are the "subclasses" of the sealed class - no matter whether I defined them all in the same file as the sealed (parent) class, or - the preferred choice - in the same package... both options should be valid choices, according to the Kotlin documentation.
Any idea, where I'm going wrong here? Thanks.
Code:
package com.tanfra.shopmob.smob.data.local.dto
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.RewriteQueriesToDropUnusedColumns
import com.tanfra.shopmob.smob.data.local.utils.*
/**
* supertype, common to all DTO types - generic part of any DTO class
* (properties declared abstract --> implementation delegated to inheriting concrete class)
*/
sealed class Dto {
abstract val id: String
abstract var itemStatus: SmobItemStatus
abstract var itemPosition: Long
}
#Entity(tableName = "smobGroups")
#RewriteQueriesToDropUnusedColumns
data class SmobGroupDTO(
#PrimaryKey #ColumnInfo(name = "groupId") override val id: String = "invalid smob group entry",
#ColumnInfo(name = "groupItemStatus") override var itemStatus: SmobItemStatus = SmobItemStatus.NEW,
#ColumnInfo(name = "groupItemPosition") override var itemPosition: Long = -1L,
#ColumnInfo(name = "groupName") var name: String = "",
#ColumnInfo(name = "groupDescription") var description: String? = "",
#ColumnInfo(name = "groupType") var type: GroupType = GroupType.OTHER,
#ColumnInfo(name = "groupMembers") var members: List<String> = listOf(),
#ColumnInfo(name = "groupActivityDate") var activityDate: String = "",
#ColumnInfo(name = "groupActivityReps") var activityReps: Long = 0,
) : Dto()
#Entity(tableName = "smobLists")
#RewriteQueriesToDropUnusedColumns
data class SmobListDTO(
#PrimaryKey #ColumnInfo(name = "listId") override val id: String = "invalid smob list id",
#ColumnInfo(name = "listItemStatus") override var itemStatus: SmobItemStatus = SmobItemStatus.NEW,
#ColumnInfo(name = "listItemPosition") override var itemPosition: Long = -1L,
#ColumnInfo(name = "listName") var name: String = "",
#ColumnInfo(name = "listDescription") var description: String? = "",
#ColumnInfo(name = "listItems") var items: List<SmobListItem> = listOf(),
#ColumnInfo(name = "listMembers") var members: List<String> = listOf(),
#ColumnInfo(name = "listLifecycleStatus") var lcStatus: SmobItemStatus = SmobItemStatus.OPEN,
#ColumnInfo(name = "listLifecycleCompletion") var lcCompletion: Double = -1.0,
) : Dto()
#Entity(tableName = "smobProducts")
#RewriteQueriesToDropUnusedColumns
data class SmobProductDTO(
#PrimaryKey #ColumnInfo(name = "productId") override val id: String = "invalid smob product id",
#ColumnInfo(name = "productItemStatus") override var itemStatus: SmobItemStatus = SmobItemStatus.NEW,
#ColumnInfo(name = "productItemPosition") override var itemPosition: Long = -1L,
#ColumnInfo(name = "productName") var name: String = "",
#ColumnInfo(name = "productDescription") var description: String? = "",
#ColumnInfo(name = "productImageUrl") var imageUrl: String? = "",
#ColumnInfo(name = "productCategoryMain") var categoryMain: ProductMainCategory = ProductMainCategory.OTHER,
#ColumnInfo(name = "productCategorySub") var categorySub: ProductSubCategory = ProductSubCategory.OTHER,
#ColumnInfo(name = "productActivityDate") var activityDate: String = "",
#ColumnInfo(name = "productActivityReps") var activityReps: Long = 0L,
#ColumnInfo(name = "productInShopCategory") var inShopCategory: ShopCategory = ShopCategory.OTHER,
#ColumnInfo(name = "productInShopName") var inShopName: String = "dummy shop",
#ColumnInfo(name = "productInShopLocation") var inShopLocation: ShopLocation = ShopLocation(0.0, 0.0),
) : Dto()
#Entity(tableName = "smobShops")
#RewriteQueriesToDropUnusedColumns
data class SmobShopDTO(
#PrimaryKey #ColumnInfo(name = "shopId") override val id: String = "invalid smob shop id",
#ColumnInfo(name = "shopItemStatus") override var itemStatus: SmobItemStatus = SmobItemStatus.NEW,
#ColumnInfo(name = "shopItemPosition") override var itemPosition: Long = -1L,
#ColumnInfo(name = "shopName") var name: String = "",
#ColumnInfo(name = "shopDescription") var description: String? = "",
#ColumnInfo(name = "shopImageUrl") var imageUrl: String? = "",
#ColumnInfo(name = "shopLocationLatitude") var locLat: Double = 0.0,
#ColumnInfo(name = "shopLocationLongitude") var locLong: Double = 0.0,
#ColumnInfo(name = "shopType") var type: ShopType = ShopType.INDIVIDUAL,
#ColumnInfo(name = "shopCategory") var category: ShopCategory = ShopCategory.OTHER,
#ColumnInfo(name = "shopBusiness") var business: List<String> = listOf()
) : Dto()
#Entity(tableName = "smobUsers")
#RewriteQueriesToDropUnusedColumns
data class SmobUserDTO(
#PrimaryKey #ColumnInfo(name = "userId") override val id: String = "invalid smob user id",
#ColumnInfo(name = "userItemStatus") override var itemStatus: SmobItemStatus = SmobItemStatus.NEW,
#ColumnInfo(name = "userItemPosition") override var itemPosition: Long = -1L,
#ColumnInfo(name = "userUsername") var username: String = "",
#ColumnInfo(name = "userName") var name: String = "",
#ColumnInfo(name = "userEmail") var email: String = "",
#ColumnInfo(name = "userImageUrl") var imageUrl: String? = ""
) : Dto()
The reason, I believe Kotlin didn't make the desired connection between the sealed class and the data classes (= subclasses) is that it still asks me for an "else" branch in "when" expressions which act upon the members of the sealed class:
package com.tanfra.shopmob.smob.data.net.nto2dto
import com.tanfra.shopmob.smob.data.local.dto.*
import com.tanfra.shopmob.smob.data.net.nto.*
import com.tanfra.shopmob.smob.data.repo.ato.Ato
// ATO --> DTO
fun <DTO: Dto, ATO: Ato> ATO._asDatabaseModel(d: DTO): DTO? {
return when (d) {
is SmobGroupDTO -> {
SmobGroupDTO(
id = (this as SmobGroupNTO).id,
itemStatus = this.itemStatus,
itemPosition = this.itemPosition,
name = this.name,
description = this.description,
type = this.type,
members = this.members,
activityDate = this.activity.date,
activityReps = this.activity.reps,
) as DTO
}
is SmobListDTO -> {
SmobListDTO(
id = (this as SmobListNTO).id,
itemStatus = this.itemStatus,
itemPosition = this.itemPosition,
name = this.name,
description = this.description,
items = this.items,
members = this.members,
lcStatus = this.lifecycle.status,
lcCompletion = this.lifecycle.completion,
) as DTO
}
is SmobProductDTO -> {
SmobProductDTO(
id = (this as SmobProductNTO).id,
itemStatus = this.itemStatus,
itemPosition = this.itemPosition,
name = this.name,
description = this.description,
imageUrl = this.imageUrl,
categoryMain = this.category.main,
categorySub = this.category.sub,
activityDate = this.activity.date,
activityReps = this.activity.reps,
inShopCategory = this.inShop.category,
inShopName = this.inShop.name,
inShopLocation = this.inShop.location,
) as DTO
}
is SmobShopDTO -> {
SmobShopDTO(
id = (this as SmobShopNTO).id,
itemStatus = this.itemStatus,
itemPosition = this.itemPosition,
name = this.name,
description = this.description,
imageUrl = this.imageUrl,
locLat = this.location.latitude,
locLong = this.location.longitude,
type = this.type,
category = this.category,
business = this.business,
) as DTO
}
is SmobUserDTO -> {
SmobUserDTO(
id = (this as SmobUserNTO).id,
itemStatus = this.itemStatus,
itemPosition = this.itemPosition,
username = this.username,
name = this.name,
email = this.email,
imageUrl = this.imageUrl,
) as DTO
}
else -> null
} // when(DTO) ... resolving generic type to concrete type
}
It's caused by your use of generics on the method signature :
fun <DTO: Dto, ATO: Ato> ATO._asDatabaseModel(d: DTO): DTO?
There's a good thread on Reddit which is very like your example. See here:
https://www.reddit.com/r/Kotlin/comments/ei8zh5/kotlin_requires_else_branch_in_when_statement/
So, to solve your problem, just change the method signature to return a type of DTO not DTO?
It's almost as if the compiler is forgetting that the DTO is a sealed class when you make it a generic parameter, so you need an exhaustive check.
As you as using is in a when statement Kotlin will smart cast the DTO to the right type anyway, so no need for the generic argument.
Here's a cut down example based on your code that works without the else:
package paul.sealed
sealed class DTO {
abstract val id: String
}
data class SmobGroupDTO(override val id: String = "invalid smob user id", val name: String = "") : DTO()
data class SmobListDTO(override val id: String = "invalid smob user id", val name: String = "") : DTO()
fun main() {
fun processDTO(dto: DTO): String {
return when (dto) {
is SmobGroupDTO -> "Group"
is SmobListDTO -> "List"
}
}
}
I am trying to make a expandable recyclerview with model data. But I am getting a signature error. Tried different solutions but didn't work.How can i set JvmName to a constructor?
Error:
Platform declaration clash: The following declarations have the same JVM signature ( (ILjava/util/List;Z)V):
RowModel class:
class RowModel {
companion object{
#IntDef(WEB_MENU, CHILD, CHILDX, CHILDXX)
#Retention(AnnotationRetention.SOURCE)
annotation class RowType
const val WEB_MENU = 1
const val CHILD = 2
const val CHILDX = 3
const val CHILDXX = 4
}
#RowType var type : Int
lateinit var webMenuItem : List<WebMenuItem>
lateinit var child: List<Child>
lateinit var childX: List<ChildX>
lateinit var childXX: List<ChildXX>
var isExpanded : Boolean
constructor (#RowType type : Int, webMenuItem: List<WebMenuItem>, isExpanded : Boolean = false){
this.type = type
this.webMenuItem = webMenuItem
this.isExpanded = isExpanded
}
constructor(#RowType type : Int, child: List<Child>, isExpanded : Boolean = false){
this.type = type
this.child = child
this.isExpanded = isExpanded
}
constructor(#RowType type : Int, childX: List<ChildX>, isExpanded : Boolean = false){
this.type = type
this.childX = childX
this.isExpanded = isExpanded
}
constructor(#RowType type : Int, childXX: List<ChildXX>, isExpanded : Boolean = false){
this.type = type
this.childXX = childXX
this.isExpanded = isExpanded
}
}
webMenuItem class:
class WebMenuItem {
val authFunctionTag: String = ""
val callFunctionName: Any = ""
val childs: MutableList<Child> = mutableListOf()
val id: Int = Int.MIN_VALUE
val isQueryWindow: Boolean = false
val menuIcon: String = ""
val menuName: String = ""
val queryServiceName: Any = ""
val queryTableName: Any = ""
val queryUniqColumnName: Any = ""
val queryUniqFieldName: Any = ""
val menuOrder: Int = ""
}
Child class:
class Child{
val authFunctionTag: String = ""
val callFunctionName: String = ""
var childs: List<ChildX> = mutableListOf()
val id: Int = Int.MIN_VALUE
val isQueryWindow: Boolean = false
val menuIcon: String = ""
val menuName: String = ""
val menuOrder: Int = Int.MIN_VALUE
val queryServiceName: String = ""
val queryTableName: String = ""
val queryUniqColumnName: String = ""
val queryUniqFieldName: String = ""
}
ChildX class:
class ChildX{
val authFunctionTag: String = ""
val callFunctionName: String = ""
var childs: List<ChildXX> = mutableListOf()
val id: Int = Int.MIN_VALUE
val isQueryWindow: Boolean = false
val menuIcon: String = ""
val menuName: String = ""
val menuOrder: Int = Int.MIN_VALUE
val queryServiceName: String = ""
val queryTableName: String = ""
val queryUniqColumnName: String = ""
val queryUniqFieldName: String = ""
}
ChildXX class:
class ChildXX{
val authFunctionTag: String = ""
val callFunctionName: String = ""
var childs: List<Any> = mutableListOf()
val id: Int = Int.MIN_VALUE
val isQueryWindow: Boolean = false
val menuIcon: String = ""
val menuName: String = ""
val menuOrder: Int = Int.MIN_VALUE
val queryServiceName: String = ""
val queryTableName: String = ""
val queryUniqColumnName: String = ""
val queryUniqFieldName: String = ""
}
Kotlin (like Java) has type erasure. The parameter with type List<Child> will be erased to List<*> after compilation, hence all your constructor overloads have the same JVM signature upon compilation.
You can get around this with factory functions with different names either at the top-level in the file, or in the companion object, e.g. RowModel.withWebMenuItem(...) and RowModel.withChild(...) and have the actual constructor for RowModel be what they all have in common:
constructor(#RowType type : Int, isExpanded : Boolean = false){
this.type = type
this.isExpanded = isExpanded
}
In my Kotlin Android codebase I have the following 2 entities..
#Entity(
tableName = ModuleConfiguration.tableName,
primaryKeys = [ModuleConfiguration.COL_ID],
foreignKeys = arrayOf(
ForeignKey(
entity = Module::class,
parentColumns = [Module.COL_ID],
childColumns = [ModuleConfiguration.COL_MODULE_ID],
onDelete = ForeignKey.CASCADE
),
ForeignKey(
entity = Group::class,
parentColumns = [Group.COL_ID],
childColumns = [ModuleConfiguration.COL_GROUP_ID]
)
)
)
class ModuleConfiguration(
#ColumnInfo(name = COL_ID)
var id: String = UUID.randomUUID().toString(),
#ColumnInfo(name = COL_TABLE)
var table: String,
#ColumnInfo(name = COL_FIELD_NAME)
var fieldName: String,
#ColumnInfo(name = COL_FIELD_LABEL)
var fieldLabel: String,
#ColumnInfo(name = COL_FIELD_TYPE)
var fieldType: ModuleConfigurationItemType,
#ColumnInfo(name = COL_GROUP_ID)
var groupId: String?,
#ColumnInfo(name = COL_MODULE_ID)
var moduleId: String,
#ColumnInfo(name = COL_POSITION)
var position: Int,
#ColumnInfo(name = COL_VISIBLE)
var visible: Int = 1, //Usually visible
#ColumnInfo(name = COL_READ_ONLY)
var readOnly: Int = 0, //Usually false
#ColumnInfo(name = COL_REQUIRED)
var required: Int = 0, //Usually false
#ColumnInfo(name = COL_CREATED_AT)
var createdAt: Long = CustomDateTimeUtil.getTodayInUTC(),
#ColumnInfo(name = COL_UPDATED_AT)
var updatedAt: Long = CustomDateTimeUtil.getTodayInUTC()
) : Cloneable, Serializable, Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
parcel.readString() ?: "",
parcel.readString() ?: "",
parcel.readString() ?: "",
fieldType = ModuleConfigurationItemType.valueOf(parcel.readString() ?: FieldType.UNKNOWN.name),
groupId = parcel.readString(),
moduleId = parcel.readString() ?: "",
position = parcel.readInt(),
visible = parcel.readInt(),
readOnly = parcel.readInt(),
required = parcel.readInt(),
createdAt = parcel.readLong(),
updatedAt = parcel.readLong()
) {
}
fun getViewType() : ModuleConfigurationItemType {
return this.fieldType
}
override fun equals(other: Any?): Boolean {
return super.equals(other)
}
override fun hashCode(): Int {
return super.hashCode()
}
override fun clone(): Any {
return super.clone()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(id)
parcel.writeString(table)
parcel.writeString(fieldName)
parcel.writeString(fieldLabel)
parcel.writeString(fieldType.name)
parcel.writeString(groupId)
parcel.writeString(moduleId)
parcel.writeInt(position)
parcel.writeInt(visible)
parcel.writeInt(readOnly)
parcel.writeInt(required)
parcel.writeLong(createdAt)
parcel.writeLong(updatedAt)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<ModuleConfiguration> {
const val tableName = "module_configuration"
const val COL_ID = "id"
const val COL_MODULE_ID = "module_id"
const val COL_TABLE = "table"
const val COL_FIELD_NAME = "field_name"
const val COL_FIELD_LABEL = "field_label"
const val COL_FIELD_TYPE = "field_type"
const val COL_GROUP_ID = "group_id"
const val COL_VISIBLE = "visible"
const val COL_READ_ONLY = "read_only"
const val COL_REQUIRED = "required"
const val COL_POSITION = "position"
const val COL_CREATED_AT = "created_at"
const val COL_UPDATED_AT = "updated_at"
const val COL_CLIENT_ID = "client_id"
override fun createFromParcel(parcel: Parcel): ModuleConfiguration {
return ModuleConfiguration(parcel)
}
override fun newArray(size: Int): Array<ModuleConfiguration?> {
return arrayOfNulls(size)
}
}
}
and Group Entity
#Entity(
tableName = Group.tableName,
primaryKeys = [Group.COL_ID]
)
class Group(
#ColumnInfo(name = COL_ID)
var id: String = UUID.randomUUID().toString(),
#ColumnInfo(name = COL_NAME)
var name: String,
#ColumnInfo(name = COL_CREATED_AT)
var createdAt: Long = CustomDateTimeUtil.getTodayInUTC(),
#ColumnInfo(name = COL_UPDATED_AT)
var updatedAt: Long = CustomDateTimeUtil.getTodayInUTC()
) : Cloneable, Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
parcel.readString() ?: "",
parcel.readLong(),
parcel.readLong()
) {
}
override fun equals(other: Any?): Boolean {
return super.equals(other)
}
override fun hashCode(): Int {
return super.hashCode()
}
override fun clone(): Any {
return super.clone()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(id)
parcel.writeString(name)
parcel.writeLong(createdAt)
parcel.writeLong(updatedAt)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Group> {
const val tableName = "group"
const val COL_ID = "id"
const val COL_NAME = "name"
const val COL_CREATED_AT = "created_at"
const val COL_UPDATED_AT = "updated_at"
const val COL_CLIENT_ID = "client_id"
override fun createFromParcel(parcel: Parcel): Group {
return Group(parcel)
}
override fun newArray(size: Int): Array<Group?> {
return arrayOfNulls(size)
}
}
}
My problem is that I am trying to set nullable foreign key, as you can see in entity named ModuleConfiguration, there is column named group_id, which is nullable.
#ColumnInfo(name = COL_GROUP_ID)
var groupId: String?,
Since, this column belongs to other entity named Group, I am trying to make it foreign key, but when I do that, I am getting following error
SQLiteConstraintException: FOREIGN KEY constraint failed (code 787)
On searching online, I found following answers on stackoverflow:
Android with Room - How to set a foreign key nullable
or
Nullable foreign key on room
but this did not help me as these answer suggest to change primitive types like int or long into non-primitive types like Integer or Long for allowing them to be null. I am already using String as type.
any help would be highly appreciated.
Thanks in advance.
I am trying to deserialize a JSON into a kotlin class using kotlin.serialization. However when the code goes to deserialize the json it throws the error kotlinx.serialization.SerializationException: Any type is not supported
Can anyone help me resolves this?
Product:
#Serializable
data class Product(
val id: Int = 0,
val name: String = "",
val slug: String = "",
val permalink: String = "",
#SerialName("date_created") val dateCreated: String = "",
#SerialName("date_created_gmt") val dateCreatedGmt: String = "",
#SerialName("date_modified") val dateModified: String = "",
#SerialName("date_modified_gmt") val dateModifiedGmt: String = "",
val type: String = "",
val status: String = "",
val featured: Boolean = false,
#SerialName("catalog_visibility") val catalogVisibility: String = "",
val description: String = "",
#SerialName("short_description") val shortDescription: String = "",
val sku: String = "",
val price: String = "",
#SerialName("regular_price") val regularPrice: String = "",
#SerialName("sale_price") val salePrice: String = "",
#SerialName("on_sale") val onSale: Boolean = false,
val purchasable: Boolean = false,
#SerialName("total_sales") val totalSales: Int = 0,
#SerialName("external_url") val externalUrl: String = "",
#SerialName("tax_status") val taxStatus: String = "",
#SerialName("tax_class") val taxClass: String = "",
#SerialName("stock_quantity") val stockQuantity: String = "",
#SerialName("stock_status") val stockStatus: String = "",
val backorders: String = "",
#SerialName("backorders_allowed") val backordersAllowed: Boolean = false,
val backordered: Boolean = false,
#SerialName("sold_individually") val soldIndividually: Boolean = false,
val weight: String = "",
val dimensions: ProductDimensions = ProductDimensions(),
#SerialName("shipping_required") val shippingRequired: Boolean = false,
#SerialName("shipping_taxable") val shippingTaxable: Boolean = false,
#SerialName("shipping_class") val shippingClass: String = "",
#SerialName("shipping_class_id") val shippingClassId: Int = 0,
#SerialName("reviews_allowed") val reviewsAllowed: Boolean = false,
#SerialName("average_rating") val averageRating: String = "",
#SerialName("rating_count") val ratingCount: Int = 0,
#SerialName("related_ids") val relatedIds: List<Int> = listOf(),
#SerialName("upsell_ids") val upsellIds: List<Int> = listOf(),
#SerialName("cross_sell_ids") val crossSellIds: List<Int> = listOf(),
#SerialName("parent_id") val parentId: Int = 0,
#SerialName("purchase_note") val purchaseNote: String = "",
val categories: List<ProductCategory> = listOf(),
val images: List<ProductImage> = listOf(),
val attributes: List<ProductAttribute> = listOf(),
val variations: List<Int> = listOf()
)
ProductDimension:
data class ProductDimensions(
val length: String = "",
val width: String = "",
val height: String = ""
)
Product Attribute:
data class ProductAttribute(
val id: Int = 0,
val name: String = "",
val position: Int = 0,
val visible: Boolean = false,
val variation: Boolean = false,
val options: List<String> = listOf()
)
Product Category:
data class ProductCategory(
val id: Int = 0,
val name: String = "",
val slug: String = ""
)
Product Image:
data class ProductImage(
val id: Int = 0,
#SerialName("date_created") val dateCreated: String = "",
#SerialName("date_created_gmt") val dateCreatedGmt: String = "",
#SerialName("date_modified") val dateModified: String = "",
#SerialName("date_modified_gmt") val dateModifiedGmt: String = "",
val src: String = "",
val name: String = "",
val alt: String = ""
)
And the associated json is on pastebin here
Here is a working cloud9 (simply run ./gradlew run) solution using the last version of Kotlin (1.3.0) and the serialization runtime (0.9.0)
val serializer = Product.serializer().list
val json = JSON.nonstrict.parse<List<Product>>(serializer, jsonString)
Note that some attributes had to have the #Optional annotation added for this serialization to work with your sample, hence the nonstrict version of the parsing.
#Serializable
data class Product(
val id: Int = 0,
val name: String = "",
val slug: String = "",
val permalink: String = "",
#Optional #SerialName("date_created") val dateCreated: String = "",
#SerialName("date_created_gmt") val dateCreatedGmt: String = "",
#SerialName("date_modified") val dateModified: String = "",
#SerialName("date_modified_gmt") val dateModifiedGmt: String = "",
val type: String = "",
val status: String = "",
val featured: Boolean = false,
#SerialName("catalog_visibility") val catalogVisibility: String = "",
val description: String = "",
#SerialName("short_description") val shortDescription: String = "",
val sku: String = "",
val price: String = "",
#SerialName("regular_price") val regularPrice: String = "",
#SerialName("sale_price") val salePrice: String = "",
#SerialName("on_sale") val onSale: Boolean = false,
val purchasable: Boolean = false,
#SerialName("total_sales") val totalSales: Int = 0,
#SerialName("external_url") val externalUrl: String = "",
#SerialName("tax_status") val taxStatus: String = "",
#SerialName("tax_class") val taxClass: String = "",
#SerialName("stock_quantity") val stockQuantity: String = "",
#Optional #SerialName("stock_status") val stockStatus: String = "",
val backorders: String = "",
#SerialName("backorders_allowed") val backordersAllowed: Boolean = false,
val backordered: Boolean = false,
#SerialName("sold_individually") val soldIndividually: Boolean = false,
val weight: String = "",
val dimensions: ProductDimensions = ProductDimensions(),
#SerialName("shipping_required") val shippingRequired: Boolean = false,
#SerialName("shipping_taxable") val shippingTaxable: Boolean = false,
#SerialName("shipping_class") val shippingClass: String = "",
#SerialName("shipping_class_id") val shippingClassId: Int = 0,
#SerialName("reviews_allowed") val reviewsAllowed: Boolean = false,
#SerialName("average_rating") val averageRating: String = "",
#SerialName("rating_count") val ratingCount: Int = 0,
#SerialName("related_ids") val relatedIds: List<Int> = listOf(),
#SerialName("upsell_ids") val upsellIds: List<Int> = listOf(),
#SerialName("cross_sell_ids") val crossSellIds: List<Int> = listOf(),
#SerialName("parent_id") val parentId: Int = 0,
#SerialName("purchase_note") val purchaseNote: String = "",
val categories: List<ProductCategory> = listOf(),
val images: List<ProductImage> = listOf(),
val attributes: List<ProductAttribute> = listOf(),
val variations: List<Int> = listOf()
)
Notice: date_created, stock_status
A good online tool to generate your data class based on your json raw data is quicktype.io
Edit: Just figured out that cloud9 had been acquired by amazon two years ago, and you can no longer create an account to see public workspace.
So here is the link to the filesystem
I've just tried this and couldn't replicate your problem. Can you maybe provide a github repo where we can see the problem?
There was one issue in the JSON in your pastebin link, which was that the stock_status value was missing, so I hit this error: kotlinx.serialization.MissingFieldException: Field stock_status is required, but it was missing
However once I added that value into the JSON I could deserialize it fine.
Here's the code I used:
import kotlinx.serialization.*
import kotlinx.serialization.json.JSON
import java.io.File
val product = JSON(strictMode = false).parseList<Product>(File("./serializationTest.json").readText())
The other thing is that according to the documentation
Using Kotlin Serialization requires Kotlin compiler 1.3.0 or higher.
Kotlin 1.3 was only officially released very recently, so are you maybe using a release candidate or something, instead of the formal release (with which it worked for me)? Maybe update all your dependencies to the latest versions and try again?