Parcelize complains "Parcelable should be a class" on objects and enums - android

When I try to annotate an enum class or object with #Parcelize, it results in the error 'Parcelable' should be a class, both as an editor hint and as a compile failure. I can #Parcelize classes just fine, but I can't do things like
#Parcelize object MySingletion : Parcelable
#Parcelize enum class Direction : Parcelable { N, E, W, S }
This happens even though the Kotlin website explicitly states that objects and enums are supported. Is there a way to fix this so that I can #Parcelize these types of classes? And ideally, is there a solution that doesn't involve manually coding the parceler logic?

Since Kotlin 1.2.60, the CHANGELOG states that Parcelize works with object and enum types.

The documented support means, that objects and enums are properly handled when used as properties on the class being parcelized. More importantly both types are implicitly excluded from the usage, as the fields have to be properties defined within the primary constructor:
#Parcelize requires all serialized properties to be declared in the primary constructor. Android Extensions will issue a warning on each property with a backing field declared in the class body. Also, #Parcelize can't be applied if some of the primary constructor parameters are not properties.
If you need to use your objects or enums as a property only, there's no issue with it. If you want to use it as a Parcelable, you can't get around implementing the interface by yourself, since both types are a kind of a singleton implementation and #Parcelize only supports types with accessible constructors with properties.

Related

android Room with kotlin value class?

I'm trying to use a room entity with a value class:
#JvmInline
value class UserToken(val token: String)
and the entity:
#Entity(tableName = TABLE_AUTH_TOKEN)
data class TokenEntity(
#PrimaryKey val id: Int = 0,
val token: UserToken
)
I get the following error:
error: Entities and POJOs must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).
public final class TokenEntity {
^
is it even possible to use room with value class? I couldn't find anything about this. thanks
See the comment from #CommonsWare. Android does not yet support value classes for Room.
The same holds true for the value classes introduced in kotlin 1.5. The type is not supported.
— Support Inline class in Room entity
Here is a possible explanation according to Kotlin Inline Classes in an Android World.
Looking to solve this you could try and add a TypeConverter for your Inline class, but since your Inline class is just the value it wraps when it’s compiled, this doesn’t make much sense and it doesn’t work as you’d expect even if you tried...
I’m just guessing it’s because this is a TypeConverter converting UserId to Int which is basically the same as Int to Int 😭. Someone will probably solve this problem, but if you have to create a TypeConverter for your Inline class then you are still plus one class for the count (multidex). 👎
I think yes if you can provide a type converter for it to change it to some sort of primitive data type (int , string, long ...etc) when it needs to be stored, and to change it back to its class type when it's fetched from database.
You can read about Type Converters from here
Referencing complex data using Room
other than that, your other class should be an entity and bind both your entities together using a Relation.
at least that's what I know about how to use Room.
UserToken always will have only one attribute? In this case, you don't need two classes, just use token: String directly on your entity class;
If you really need keep this class, you have two options:
TypeConverter, where you basically will convert the object into a json, and save as string in the database;
Relation, where you will transform the UserToken in a entity, and on TokenEntity save the tokenId.

Proguard: keep data class member information that has property with specific annotation

I am currently creating a library for private use which provides an Annotation (lets call it #Something) which can be used on Properties of a data class. I created the annotation like so:
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.PROPERTY)
annotation class Something
It will be used like this
data class SomeDataClass (val param1: String, #Something val param2: String, val param3: String)
I then want to be able to access the following things on the class that contains properties with this annotation:
memberFunctions (to get the copy constructor)
parameters of the copy constructor
memberProperties
property annotations
property name
List item
Now everything works properly until I minify my library with ProGuard. As I understand it, I need to describe my ProGuard rules in consumer-rules.pro. But what exactly do I need to add here? I want every data class in the application that uses my library that has a property annotated with #Something to be kept so I can read the things above from it.

Is there better way for handle kotlinx serialization?

I use kotlinx.serialization on Kotlin native project, I a defined Super class for my models and all of the models extends from it.
I defined a function to called toJSON() for serialize variables and fields inside model that all of class models have it.
#Serializable
open class Model {
fun toJSON(): String = JSON.stringify(this);
}
And I created a subclass
class Me : Model() {
var name:String = "Jack";
}
but when I invoke JSON.stringify(this), IDE get a Warning to me:
This declaration is experimental and its usage must be marked with '#kotlinx.serialization.ImplicitReflectionSerializer' or '#UseExperimental(kotlinx.serialization.ImplicitReflectionSerializer::class)'
I paid attention and I used #ImplicitReflectionSerializer annotation while not worked.
Where is my problem?
This is discussed here. It's the particular overload you're using which is still experimental. So your options are either to use the other overload (which takes in a serializer) or to use one of the annotations mentioned in the error message. If you look at the answer to the question I linked (and the comments following it), you'll see it talks about using #UseExperimental and where it should be used.

How to integrate Kotlin inline class with Android data binding?

Kotlin introduced inline class which is strong typed type alias. This can be useful when use with database. For example,
inline class Age(val value: Int)
inline class Height(val value: Int)
When they are written to database, they are compiled to Int but Kotlin can prevent you accidentally putting a Height into a Age Field. If you use type alias or Int directly, it is possible with type alias but inline class produces a compile time error.
However, these also cause problems with Android data binding. I get data binding error when I try to bind a String inline class to a String attribute.
While it is possible to write some kinds of adapter to bypass this, but it defeat the purpose of using inline class and not practical for creating adapters for all inline classes.
I would like to ask are there any elegant ways to solve this issue?
First thing you need to understand is inline classes are not just wrappers around primitive types. They are more than type Aliases.
Now coming to your example, even though DataBinding has the understanding that if you put any MutableLiveData<T> instance in xml, it will take that value of that particular variable(something like mutableLiveData.value). But if you put MutablLiveData<Age>, mutableLiveData.value will always be of Type Age but not type Int.
Note that inline class, creates a completely new type and not just a type alias.
I believe that you somehow need a method in your data binding, that returns the value contained in the inline class object.

How to use satyan's Sugar ORM with #Table annotation

Im very statisfied with SugarOrm for Android, but I ran into an issue. I'm using it with GSON for Json serializations and I want to get rid of SugarRecord's id attribute. I know I should use #Table annotation and later exclude specific field from serialization using #Expose, but after annotating class with #Table I cannot use .save(), delete(),... methods on the object, as it is the case extending SugarRecord. I don't know how to persist objects using #Table annotation.
I found the documentation here very limited.
The document hasn't been updated for the annotation based persistence yet. The methods save(), delete() will be available as static methods on SugarRecord class.
So instead of doing this:
object.save()
You'd be doing this:
SugarRecord.save(object)
Check out some tests here to understand better.
https://github.com/satyan/sugar/tree/master/example/src/test/java/com/example/sugartest

Categories

Resources