Pages

Friday 16 February 2018

TypeConverters with Custom Types, Static or Instance Methods? | Android Room Persistence Library



There's all the useless copy and paste tutorials out there that only use the Date object. Congratulations authors, on adding nothing to the world. Then there is the inconsistency on whether the @TypeConverter methods should be static or instance. I'll sort this out in this tutorial.


1. Static, or Instance, @TypeConverter Methods?

Short Answer: It doesn't matter, choose which ones you want to use. The generated code will account for this.

I looked at the generated code, as I was using static methods for the Date Converters and instance methods for my custom types Collection Converters.

1.1. Static Methods

The generated code, used static calls and it didn't make an attempt to make an instance out of the Date Converters class.

Static Declatation
public class DateConverters {

  @TypeConverter
  public static Long dateToTimestamp(Date date) { ... }
  ...
}



Generated Code from Static Declaration
public BikeRaceDao_Impl(RoomDatabase __db) {
  ...
  final Long _tmp =
    DateConverters.dateToTimestamp(
        value.getStartDate());
  ...
}

1.2. Instance Methods

The generated code, made an instance of the CollectionConverters class and used the methods with the instance.

Instance Declaration

public class CollectionConverters {

  @TypeConverter
  public String stringSetToString(Set<String> stringSet);
  ...
}

Generated Code from Instance Declaration
public class ProfileFilterDao_Impl
           implements ProfileFilterDao {
  ...
  private final CollectionConverters __collectionConverters =
      new CollectionConverters();
  ...
  public ProfileFilterDao_Impl(RoomDatabase __db) {
    ...
    _tmp_1 =
        __collectionConverters.stringSetToString(
            value.getCategories());
    ...
  }
}

1.3. Conclusion

I would suggest that we use Static methods, with a private constructor to prevent instances of these classes being misused, as per Effective Java 3rd Edition Item Four: Enforce noninstantiability with a private constructor.


2. @TypeConverter methods with Custom Types

As I've said in the Conclusion above, I've gone for static methods with a private constructor. I am using GSON to convert my POJOs to JSON for storage in the database.


/**
 * Converters for the RoomDatabase.
 * This class keeps the Converters for Collections together.
 */
public class CollectionConverters {

  @TypeConverter
  public static String stringSetToString(
           Set<String> stringSet) {

    return (stringSet == null || stringSet.isEmpty()) ?
        null : new Gson().toJson(stringSet);
  }

  @TypeConverter
  public static Set<String> stringToStringSet(
           String string) {

    if (string == null || string.isEmpty())
        return null;

    Type setType =
        new TypeToken<HashSet<String>>() {}.getType();

    return new Gson().fromJson(string, setType);
  }

  @TypeConverter
  public static String raceTypeSetToString(
           Set<RaceType> raceTypeSet) {

    return (raceTypeSet == null || raceTypeSet.isEmpty()) ?
        null : new Gson().toJson(raceTypeSet);
  }

  @TypeConverter
  public static Set<RaceType> stringToRaceTypeSet(
           String string) {

    if (string == null || string.isEmpty()) return null;

    Type setType =
        new TypeToken<HashSet<RaceType>>() {}.getType();

    return new Gson().fromJson(string, setType);
  }

  /**
   * Preventing Instancing with a Private Constructor.
   */
  private CollectionConverters() {
    throw new AssertionError(
      "Class should not be instantiated");
  }
}

Thank you for reading and I hope this helped.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.