How to use auto-value with firebase 9.2 in Android
Asked Answered
S

2

6

I want to use auto-value with firebase 9.2.0+. I have the following code:

@AutoValue
public abstract class Office {

    public static Builder builder() {
        return new AutoValue_Office.Builder();
    }

    public abstract double latitud();
    public abstract double longitud();

    @AutoValue.Builder
    public static abstract class Builder {

        public abstract Builder latitud(double latitud);
        public abstract Builder longitud(double longitud);

        public abstract Office build();

    }

}

But when I make to call this Office office = childDataSnapshot.getValue(Office.class); I am getting this error:

com.google.firebase.database.DatabaseException: No properties to serialize found on class com.example.app.model.Office

Somebody have an idea why I am getting this error and how to solve it? I read that firebase is no longer using jackson for json serialization. So I am not sure how to specify a kind of @JsonProperty("latitud") I have used @PropertyName unsuccessfully.

I also tried rename the abstract methods like public abstract double getLatitud(); and after that the error is the next one:

java.lang.InstantiationException: Can't instantiate abstract class com.example.app.model.Office

So I am not sure how to solve this.

SOLUTION

Thanks to hatboysam and Frank van Puffelen I finally could face this problem with the next solution.

  1. I created a FirebaseUtil enum with two methods for serialize and deserialize objects for Firebase based on hatboysam answer and Frank van Puffelen comment.
  2. I create a couple of User and Phone classes for testing.
  3. Dependencies:

    compile 'com.fasterxml.jackson.core:jackson-annotations:2.8.0'
    compile 'com.fasterxml.jackson.core:jackson-databind:2.8.0'
    
  4. Usage example:

    User user = FirebaseUtil.deserialize(dataSnapshot, User.class);
    Map<String, Object> map = FirebaseUtil.serialize(user);
    
Soy answered 8/7, 2016 at 7:42 Comment(1)
One question: what is the purpose behind using Auto-Value ? For making Parcelable ?Grope
H
4

I'm not sure this is possible with the default Firebase data mapper, but there is a possible workaround. First let's explain the errors you're seeing:

com.google.firebase.database.DatabaseException: No properties to serialize found on class com.example.app.model.Office

The Firebase mapper looks for either public fields or fields named with the getFoo/setFoo pattern. So on your class the mapper does not see any properties.

java.lang.InstantiationException: Can't instantiate abstract class com.example.app.model.Office

This is the one I think you'll have trouble getting around. In order for the deserialization to work your class needs to have a public, no-argument constructor that the mapper can call via reflection (newInstance()). As far as I know this is not how AutoValue works.

But don't lose hope!. According to this github issue there is a way to make Jackson and AutoValue compatible using the @JsonCreator annotation. So you'll need to use both Jackson and Firebase to get the job done here.

Serializing:

// Convert to a Map<String,Object> using Jackson and then pass that to Firebase
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> map = mapper.convertValue(office, Map.class);
databaseReference.setValue(map);

Deserializing:

// Use Firebase to convert to a Map<String,Object>
GenericTypeIndicator<Map<String,Object>> t = new GenericTypeIndicator<Map<String,Object>>() {};
Map<String,Object> map = dataSnap.getValue(t);

// Use Jackson to convert from a Map to an Office object
ObjectMapper mapper = new ObjectMapper();
Office pojo = mapper.convertValue(map, Office.class);
Hildegardhildegarde answered 8/7, 2016 at 14:59 Comment(4)
Yeah, sorry I forgot to mention that I tried that workaround unsuccessfully, as I could read/research firebase is not using Jackson anymore. So this work around does not worked for me :/Soy
@Soy what exactly about that workaround does not work for you? While Firebase does not use Jackson internally anymore you can still use Jackson as a companion to firebase.Hildegardhildegarde
To learn how to use Jackson with the latest Firebase SDKs, see #37547899Laith
Never mind, I was trying wrong code. I'll update my question with my solution. Thank you very much for you hep guys.!Soy
R
0

I wrote an AutoValue extension for this:

https://github.com/mattlogan/auto-value-firebase

The extension generates a firebase-compatible class, called FirebaseValue, as a static inner class in your generated AutoValue class. You can convert between your AutoValue class and your FirebaseValue class via the generated constructors.

Here's an example, copied from the readme, of what that looks like:

@AutoValue @FirebaseValue
public abstract class Taco {

  public static Taco create(String name, List<Ingredient> ingredients, Review review) {
    return new AutoValue_Taco(name, ingredients, review);
  }

  // Create AutoValue_Taco instance from AutoValue_Taco.FirebaseValue instance
  public static Taco create(DataSnapshot dataSnapshot) {
    AutoValue_Taco.FirebaseValue taco = dataSnapshot.getValue(AutoValue_Taco.FirebaseValue.class);
    return new AutoValue_Taco(taco);
  }

  // Create AutoValue_Taco.FirebaseValue instance from AutoValue_Taco instance
  public Object toFirebaseValue() {
    return new AutoValue_Taco.FirebaseValue(this);
  }

  public abstract String name();

  public abstract List<Ingredient> ingredients();

  public abstract Review review();
}
Riplex answered 13/8, 2016 at 16:50 Comment(3)
Nice! sounds very good! I'll take a look this weekend man, good job! :)Soy
Does it support Firestore and DocumentSnapshot?Unguiculate
@Unguiculate Sorry, no it doesn't. I switched to Kotlin a while ago and haven't used AutoValue since! If you're looking for an open source project though, feel free to open a PR :)Riplex

© 2022 - 2024 — McMap. All rights reserved.