Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use auto-value with firebase 9.2 in Android

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);
    
like image 269
epool Avatar asked Jul 08 '16 07:07

epool


Video Answer


1 Answers

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);
like image 91
Sam Stern Avatar answered Oct 26 '22 20:10

Sam Stern