epool epool - 4 months ago 274
Java Question

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 for the 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. Usage example:

    User user = FirebaseUtil.deserialize(dataSnapshot, User.class);
    Map<String, Object> map = FirebaseUtil.serialize(user);


Answer

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);
Comments