7

https://github.com/neuberfran/JThings/blob/main/app/src/main/java/neuberfran/com/jfran/model/FireFran.kt

I have this POJO above with the error mentioned in the topic. I know it is a mistake already mentioned here, but I have tried several classes (besides this one) and I have not been successful, since my model/POJO class (and Code implementation) is different from several that I saw:(Every help is welcome)

Could not deserialize object. Class does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped (found in field 'value')

enter image description here enter image description here Change made to the garagem document, exchanged value for valorb, etc...

enter image description here

neuberfran
  • 359
  • 3
  • 18

3 Answers3

16

The error is very clear, your class "FireFran" doesn't have a no-argument constructor. When you try to deserialize an object from Cloud Firestore, the Android SDKs require that the class must have a default no-arg constructor and also setters that map to each database property.

In Kotlin, the data classes don't provide a default no-arg constructor. So you need somehow ensure the compiler that all the properties have an initial value. You can provide to all of the properties an initial value of null or any other value you find more appropriate.

So your "FireFran" might look like this:

class FireFran(
    var alarmstate: Boolean  = false,
    var garagestate: Boolean = false,
    var id: String? = null,
    var userId: String? = null,
    var value: FireFranValue? = null //Newly added
) {
    //var value: FireFranValue = FireFranValue(false, 0)
    companion object Factory {
        fun create() :FireViewModel = FireViewModel()
        var COLLECTION = "device-configs"
        var DOCUMENT = "alarme"
        var FIELD_userId = "userId"
    }
}

Now adding the properties in the constructor, Kotlin will automatically generate a default no-arg constructor. In this way, the Firebase Android SDK will be able to use. It will also generate setters for each property. Please see that each property is var and not a val, and provides a default null value in case of "id" and "userId".

If don't make this change, you won't be able to use automatic deserialization. You'll have to read the value for each property out of the DocumentSnapshot object and pass them all to Kotlin's constructor.

Edit:

  1. In your screenshot, the "value" property is on an object of type "FireFranValue", which has only two properties, "brightness" and "on". To be able to read the data under "value", your "FireFran" class should contain a new property of type "FireFranValue". Please check above the class.

  2. If you don't want to use automatic deserialization, you can get the value of each property individually. For example, you can get the value of the "userId" property using DocumentSnapshot's getString(String field) method:

     val userId = snapshot.getString("userId")
    

Edit2:

Your three classes should look like this:

class FireFran(
    var alarmstate: Boolean  = false,
    var garagestate: Boolean = false,
    var id: String? = null,
    var userId: String? = null,
    var owner: String? = null,
    var value: FireFranValue = FireFranValue(false),
    var valorb: FireFranValueB = FireFranValueB(openPercent = 0)
)
data class FireFranValue(
    var on: Boolean // = false
)

data class FireFranValueB(
    var openPercent: Number // = 0
)

Edit3:

class FireFran(
    var alarmstate: Boolean  = false,
    var garagestate: Boolean = false,
    var id: String? = null,
    var userId: String? = null,
    var owner: String? = null,
    var value: FireFranValue? = null,
    var valorb: FireFranValueB? = null
)
data class FireFranValue(
    var on: Boolean? = null
)

data class FireFranValueB(
    var openPercent: Number? = null
)

Now, "on" and "openPercent" will get the values from the database.

Please check the following class declaration:

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • 1
    Tks. But unfortunately, don't make change in the topic error(Could not deserialize object. Class does not define a no-argument constructor...found in field 'value') I integrated the data class FireFranValue to your code above, which evidently still seems to be necessary: https://gist.github.com/neuberfran/f365cd98c6799ad3941731e99094f185 "you won't be able to use automatic deserialization. You'll have to read the value for each property out of the DocumentSnapshot object and pass them all to Kotlin's constructor." – neuberfran Mar 29 '21 at 15:58
  • 2
    Yes, both FireFran and FireFranValue must have the no-argument constructor. For the `value` you should also add another property of type FireFranValue in the class. Does it work now? – Alex Mamo Mar 29 '21 at 16:11
  • 1
    Neither of the two POJO below work and have the same error: https://gist.github.com/neuberfran/f365cd98c6799ad3941731e99094f185 https://gist.github.com/neuberfran/720248d99e36462b1447ff969c711014 Do you could clarify the two things you said?: 1) "For the value you should also add another property of type FireFranValue in the class" 2) "If don't make this change, you won't be able to use automatic deserialization. You'll have to read the value for each property out of the DocumentSnapshot object and pass them all to Kotlin's constructor" – neuberfran Mar 29 '21 at 18:04
  • 2
    Please check my updated answer. Is it clear now? – Alex Mamo Mar 29 '21 at 18:37
  • 1
    https://drive.google.com/file/d/1B2oBz7XR5ziyN_FMMTk2uZZkmAJ9zIsQ/view – neuberfran Mar 29 '21 at 19:08
  • 1
    Thank you, it's getting clearer and clearer. But, for now, I have the error above (photo described in the link) – neuberfran Mar 29 '21 at 20:07
  • 2
    Yes, in that image I see a variable naming issue. So the fields should remain "value", as it is in the database, and change the second one. Or simply comment line 14. Does it work now? – Alex Mamo Mar 30 '21 at 06:31
  • 1
    Not work yet. I comment line 14. Not solved yet: https://drive.google.com/file/d/1KmxKRVV59gDoTXkfE3Ztg59xTh5RgDUW/view?usp=sharing – neuberfran Mar 30 '21 at 13:25
  • 2
    Creating a new object of your "FireFranValue" class doesn't help there. Besides that, all objects should have **different names**. Give it try again. – Alex Mamo Mar 30 '21 at 14:08
  • 1
    Not solved yet. But I made changes to the firestore structure: I got brightness in the alarm and I changed the value to the valorb field in the garage. In the part of FireFran.kt I made changes (due to the previous changes mentioned) and put owner field (which is not used in the android-app, but is part of the firestore): https://gist.github.com/neuberfran/16acf3a1f26ed5034e8976a40d8b6bf2 https://gist.github.com/neuberfran/697ae43766f14a2517399962b2cadb01 https://drive.google.com/file/d/1rsZQ761t5VBhHHpufDCpv1r-IfJ6nten/view?usp=sharing – neuberfran Mar 31 '21 at 00:25
  • 3
    I'm not sure how are these changes related to your initial question, but the entire idea is to have the no-argument constructor for class and inner classes. Keep me posted. – Alex Mamo Mar 31 '21 at 05:51
  • 1
    You said: "all objects should have different names" and you said: "I'm not sure how are these changes related to your initial question". I made all the changes to resolve what you said (about different names) and resolve the issue of the topic. I would like you to make changes to your answer above. These // na in var value: FireFranValue = FireFranValue (false, 0) already solves an error(no topic issue). But you still need to include valorb and FireFranValueB and owner – neuberfran Mar 31 '21 at 14:55
  • 2
    Yes, all objects should have different names. There is no way you can have two fields with the same name. Tou added a new class in your code "FireFranValueB". That class and the corresponding property "valorb" (from the database) will not solve your actual problem. If you need a new property called "valorb", you should map that property to an object of type "FireFranValueB". But you still need to have different names in your class, right? – Alex Mamo Mar 31 '21 at 15:19
  • 1
    Answering your question I did it already and it didn't solve it. You can analyze the codes that I had already sent you in my previous answer and send it now again: https://gist.github.com/neuberfran/697ae43766f14a2517399962b2cadb01 https://gist.github.com/neuberfran/16acf3a1f26ed5034e8976a40d8b6bf2 but topic issue not solved – neuberfran Mar 31 '21 at 16:10
  • 2
    Please check my updated answer. Does it work now? – Alex Mamo Mar 31 '21 at 16:16
  • 2
    With the new changes, can you get the desired data? The companion object can be placed in the class. – Alex Mamo Mar 31 '21 at 19:34
  • 2
    What exactly is left now? – Alex Mamo Apr 01 '21 at 11:21
  • 1
    https://drive.google.com/file/d/1Xx3mUphYR5bob9K7ClkR5TRqr3c4Wxbx/view?usp=sharing (Could not deserialize object. Class neuberfran.com.jfran.model.FireFranValue does not define a no-argument constructor. If you are using ProGuard, make sure these constructors are not stripped (found in field 'value')) – neuberfran Apr 01 '21 at 13:21
  • 3
    In see. Please check my last edit (Edit3). Does it work now? – Alex Mamo Apr 01 '21 at 14:36
  • 1
    No. not work(same mistake). You always forget to put the companion object: https://gist.github.com/neuberfran/fc87fcff319c1c1f361524336df2e1a2 – neuberfran Apr 01 '21 at 16:10
  • 1
    https://drive.google.com/file/d/1djr9BsibHFL65wP4v99IvG6eFHxPaHNk/view As you can see in this photo of the drive, I received an email from the firestore support asking me to pay attention to proGuard, which is where the issue solution should be. I'm really using proGuard, I tried to comment on the line, but it didn't solve the issue of this topic (it remained). They talk about documentation that is this of this link: https://www.guardsquare.com/en/products/proguard/manual/examples#serializable Would you know how to analyze what can be done and corrected in my proGuard??? – neuberfran Apr 02 '21 at 03:13
  • 2
    I might take a look at this **[answer](https://stackoverflow.com/questions/60719791/firebase-firestore-variable-name-changed/60719948#60719948)**, does it help? – Alex Mamo Apr 02 '21 at 09:47
  • 1
    Could not deserialize object. Deserializing values to Number is not supported (found in field 'valorb.openPercent') https://drive.google.com/file/d/1K0seKHHlDWEYOHlB5cuoN0xV4l8jSXbK/view?usp=sharing This is correct or NOT?: https://drive.google.com/file/d/1kdKY7nm6kOgXsHX4kF7EDk6za3S0eWSp/view?usp=sharing – neuberfran Apr 02 '21 at 15:58
  • 2
    Is "openPercent" not a number? Besides that, all classes should be added to the ProGuard rules, including the sub-classes. – Alex Mamo Apr 02 '21 at 16:54
  • 1
    my repo updated https://github.com/neuberfran/JThings/blob/main/app/proguard-rules.pro – neuberfran Apr 02 '21 at 16:58
  • 1
    openPercent is a Number. 0 or 100. – neuberfran Apr 02 '21 at 22:29
  • 1
    Would I be able to edit your answer by placing the correct proguard-rules.pro that I should use? – neuberfran Apr 03 '21 at 16:25
  • 1
    Could not deserialize object. Deserializing values to Number is not supported (found in field 'valorb.openPercent') -> valorb is type map, and openPercent is type number – neuberfran Apr 03 '21 at 20:09
  • 1
    I'm changing the project. I think the issue is not in proGuard. I ask you to assist me in this new issue. My new pojo/ model class is based on this link:https://stackoverflow.com/questions/58195250/android-firestore-toobject-cannot-deserialize-an-object-with-a-nested-array And this is my issue and new data class FireFran: https://gist.github.com/neuberfran/59ba8e5162a864ecc5c3a64d2b0be257 https://drive.google.com/drive/folders/1v0qkT1YGhV19YwqyhMiTVY61KQ7TThoj?usp=sharing – neuberfran Apr 07 '21 at 13:36
  • 2
    @NEUBERSOUSA Your new class looks good to me. What's the problem now? – Alex Mamo Apr 07 '21 at 14:33
  • 1
    https://drive.google.com/file/d/1pndcfX9_jQnl5WZLP4G5nCTIKQagvgd3/view?usp=sharing this is my problem now: I need transform a List – neuberfran Apr 07 '21 at 15:38
  • 1
    photo with complete line of the issue: https://drive.google.com/file/d/1cPQ4kAMCX4y0SGT9NKbISvNZJY4hLMk0/view?usp=sharing – neuberfran Apr 07 '21 at 16:38
  • value it's a List not a boolean so it can be used in an if statement, right? For other issues, please post another question. – Alex Mamo Apr 08 '21 at 07:07
  • how to transpose List to – neuberfran Apr 08 '21 at 13:26
  • You cannot. There is no way you can cast an object of type List to Boolean. You should have the same data type in both places. – Alex Mamo Apr 08 '21 at 14:48
  • Thanks. Of course, I know about (✔️) and green. But None of the 3 responses (edit 1/2/3) that you suggested) worked. There is no reason why I choose your answer as correct now. – neuberfran Apr 08 '21 at 17:44
  • Hi there. Could you please how does keyword "inner" affect the error? I am getting the same error when my inner class is defined with the "inner" keyword (even though I have a no argument constructor). Once I remove "inner" keyword, the error goes away... – Liker777 Oct 29 '21 at 05:09
3

You can define a no-arg constructor in kotlin like this:

data class SampleClass(
    val field1: String,
    val field2: String
) {
    constructor(): this("", "")
}
Hamza Maqsood
  • 355
  • 2
  • 11
0

First thing: It was not necessary to create the field (map type) called valorb. It was resolved with value.openPercent

As I have two documents (alarme and garagem) I created two POJO classes (FireFran and FireFranB)

https://github.com/neuberfran/JThingsFinal/blob/main/app/src/main/java/neuberfran/com/jfran/model/FireFranB.kt

The secret was to treat the value.on and value.openPercent fields as maps (as facts are):

enter image description here

neuberfran
  • 359
  • 3
  • 18