Reputation:
I'm willing to try the new Room Library from Android and I met the below error:
Error:(19, 29) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
This error refers to the following class member:
private HashSet<String> fruits;
I have the following class:
@Entity(tableName = "SchoolLunches")
public class SchoolLunch {
@PrimaryKey(autoGenerate = true)
private int lunchId;
private boolean isFresh;
private boolean containsMeat;
private HashSet<String> fruits;
public int getLunchId() {
return lunchId;
}
public void setLunchId(int lunchId) {
this.lunchId = lunchId;
}
public boolean isFresh() {
return isFresh;
}
public void setFresh(boolean fresh) {
isFresh = fresh;
}
public boolean isContainsMeat() {
return containsMeat;
}
public void setContainsMeat(boolean containsMeat) {
this.containsMeat = containsMeat;
}
public HashSet<String> getFruits() {
return fruits;
}
public void setFruits(HashSet<String> fruits) {
this.fruits = fruits;
}
Also, there is a relative DAO class:
@Dao
public interface SchoolLunchDAO {
@Query("SELECT * FROM SchoolLunches")
List<SchoolLunch> getAll();
@Insert
void insertAll(SchoolLunch... schoolLunches);
@Query("DELETE FROM SchoolLunches")
void deleteAll();
}
Since I'm trying to be a very good developer, I wrote a unit test as follows:
@Test
public void singleEntityTest() {
HashSet<String> fruitSet = new HashSet<>();
fruitSet.add("Apple");
fruitSet.add("Orange");
SchoolLunch schoolLunch = new SchoolLunch();
schoolLunch.setContainsMeat(false);
schoolLunch.setFresh(true);
schoolLunch.setFruits(fruitSet);
schoolLunchDAO.insertAll(schoolLunch);
List<SchoolLunch> schoolLunches = schoolLunchDAO.getAll();
assertEquals(schoolLunches.size(), 1);
SchoolLunch extractedSchoolLunch = schoolLunches.get(0);
assertEquals(false, extractedSchoolLunch.isContainsMeat());
assertEquals(true, extractedSchoolLunch.isFresh());
assertEquals(2, extractedSchoolLunch.getFruits().size());
}
What should I do here?
Upvotes: 2
Views: 1131
Reputation: 1006944
What should I do here?
You could create a type converter, as suggested by the error message. Room does not know how to persist a HashSet<String>
, or a Restaurant
, or other arbitrary objects.
Step #1: Decide what basic type you want to convert your HashSet<String>
into (e.g., a String
)
Step #2: Write a class with public static
type conversion methods, annotated with @TypeConverter
, to do the conversion (e.g., HashSet<String>
to String
, String
to HashSet<String>
), in some safe fashion (e.g., use Gson, formatting your String
as JSON)
Step #3: Add a @TypeConverters
annotation to your RoomDatabase
or other scope, to teach Room about your @TypeConverter
methods
For example, here are a pair of type converter methods for converting a Set<String>
to/from a regular String
, using JSON as the format of the String
.
@TypeConverter
public static String fromStringSet(Set<String> strings) {
if (strings==null) {
return(null);
}
StringWriter result=new StringWriter();
JsonWriter json=new JsonWriter(result);
try {
json.beginArray();
for (String s : strings) {
json.value(s);
}
json.endArray();
json.close();
}
catch (IOException e) {
Log.e(TAG, "Exception creating JSON", e);
}
return(result.toString());
}
@TypeConverter
public static Set<String> toStringSet(String strings) {
if (strings==null) {
return(null);
}
StringReader reader=new StringReader(strings);
JsonReader json=new JsonReader(reader);
HashSet<String> result=new HashSet<>();
try {
json.beginArray();
while (json.hasNext()) {
result.add(json.nextString());
}
json.endArray();
}
catch (IOException e) {
Log.e(TAG, "Exception parsing JSON", e);
}
return(result);
}
Upvotes: 3
Reputation:
I created the following class and now it works. Thank you, CommonsWare!
public class Converters {
private static final String SEPARATOR = ",";
@TypeConverter
public static HashSet<String> fromString(String valueAsString) {
HashSet<String> hashSet = new HashSet<>();
if (valueAsString != null && !valueAsString.isEmpty()) {
String[] values = valueAsString.split(SEPARATOR);
hashSet.addAll(Arrays.asList(values));
}
return hashSet;
}
@TypeConverter
public static String hashSetToString(HashSet<String> hashSet) {
StringBuilder stringBuilder = new StringBuilder();
for (String currentElement : hashSet) {
stringBuilder.append(currentElement);
stringBuilder.append(SEPARATOR);
}
return stringBuilder.toString();
}
}
Upvotes: 2