-
-
Save NiPfi/f00dc0f8178ef907202ed1046ced2746 to your computer and use it in GitHub Desktop.
package ch.jojoni.jamplan.model.repository; | |
import android.support.annotation.NonNull; | |
import android.util.Log; | |
import com.google.android.gms.tasks.Continuation; | |
import com.google.android.gms.tasks.OnFailureListener; | |
import com.google.android.gms.tasks.Task; | |
import com.google.firebase.firestore.CollectionReference; | |
import com.google.firebase.firestore.DocumentReference; | |
import com.google.firebase.firestore.DocumentSnapshot; | |
import com.google.firebase.firestore.FirebaseFirestore; | |
import ch.jojoni.jamplan.model.Identifiable; | |
/** | |
* Manages data access for Firebase | |
*/ | |
public class FirestoreRepository<TEntity extends Identifiable<String>> implements Repository<TEntity, String> { | |
private static final String TAG = "FirestoreRepository"; | |
private final Class<TEntity> entityClass; | |
private final CollectionReference collectionReference; | |
private final String collectionName; | |
/** | |
* Initializes the repository storing the data in the given collection. Should be from {@link FirestoreCollections}. | |
*/ | |
public FirestoreRepository(Class<TEntity> entityClass, String collectionName) { | |
this.collectionName = collectionName; | |
this.entityClass = entityClass; | |
FirebaseFirestore db = FirebaseFirestore.getInstance(); | |
this.collectionReference = db.collection(this.collectionName); | |
} | |
@Override | |
public Task<Boolean> exists(final String documentName) { | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Checking existence of '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.get().continueWith(new Continuation<DocumentSnapshot, Boolean>() { | |
@Override | |
public Boolean then(@NonNull Task<DocumentSnapshot> task) { | |
Log.d(TAG,"Checking if '" + documentName + "' exists in '" + collectionName +"'."); | |
return task.getResult().exists(); | |
} | |
}); | |
} | |
@Override | |
public Task<TEntity> get(String id) { | |
final String documentName = id; | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Getting '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.get().continueWith(new Continuation<DocumentSnapshot, TEntity>() { | |
@Override | |
public TEntity then(@NonNull Task<DocumentSnapshot> task) throws Exception { | |
DocumentSnapshot documentSnapshot = task.getResult(); | |
if (documentSnapshot.exists()) { | |
return documentSnapshot.toObject(entityClass); | |
} else { | |
Log.d(TAG, "Document '" + documentName + "' does not exist in '" + collectionName + "'."); | |
return entityClass.newInstance(); | |
} | |
} | |
}); | |
} | |
@Override | |
public Task<Void> create(TEntity entity) { | |
final String documentName = entity.getEntityKey(); | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Creating '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.set(entity).addOnFailureListener(new OnFailureListener() { | |
@Override | |
public void onFailure(@NonNull Exception e) { | |
Log.d(TAG, "There was an error creating '" + documentName + "' in '" + collectionName + "'!", e); | |
} | |
}); | |
} | |
@Override | |
public Task<Void> update(TEntity entity) { | |
final String documentName = entity.getEntityKey(); | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Updating '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.set(entity).addOnFailureListener(new OnFailureListener() { | |
@Override | |
public void onFailure(@NonNull Exception e) { | |
Log.d(TAG, "There was an error updating '" + documentName + "' in '" + collectionName + "'.", e); | |
} | |
}); | |
} | |
@Override | |
public Task<Void> delete(final String documentName) { | |
DocumentReference documentReference = collectionReference.document(documentName); | |
Log.i(TAG, "Deleting '" + documentName + "' in '" + collectionName + "'."); | |
return documentReference.delete().addOnFailureListener(new OnFailureListener() { | |
@Override | |
public void onFailure(@NonNull Exception e) { | |
Log.d(TAG, "There was an error deleting '" + documentName + "' in '" + collectionName + "'.", e); | |
} | |
}); | |
} | |
} |
package ch.jojoni.jamplan.model; | |
import com.google.firebase.firestore.Exclude; | |
/** | |
* Represents an object that can be uniquely identified among other objects of the same type | |
* by using an UID. | |
* | |
* @param <TKey> type of the unique key (UID) this object is uniquely identified by. The type needs | |
* a correct implementation of its equals() method or the behaviour of code using this | |
* interface will be undefined. | |
*/ | |
public interface Identifiable<TKey> { | |
@Exclude | |
TKey getEntityKey(); | |
} |
package ch.jojoni.jamplan.model.repository; | |
import com.google.android.gms.tasks.Task; | |
import ch.jojoni.jamplan.model.Identifiable; | |
/** | |
* Manages data access for POJOs that are uniquely identifiable by a key, such as POJOs implementing {@link Identifiable}. | |
*/ | |
public interface Repository<TEntity extends Identifiable<TKey>, TKey> { | |
/** | |
* Checks the repository for a given id and returns a boolean representing its existence. | |
* @param id the unique id of an entity. | |
* @return A {@link Task} for a boolean which is 'true' if the entity for the given id exists, 'false' otherwise. | |
*/ | |
Task<Boolean> exists(TKey id); | |
/** | |
* Queries the repository for an uniquely identified entity and returns it. If the entity does | |
* not exist in the repository, a new instance is returned. | |
* @param id the unique id of an entity. | |
* @return A {@link Task} for an entity implementing {@link Identifiable}. | |
*/ | |
Task<TEntity> get(TKey id); | |
/** | |
* Stores an entity in the repository so it is accessible via its unique id. | |
* @param entity the entity implementing {@link Identifiable} to be stored. | |
* @return An {@link Task} to be notified of failures. | |
*/ | |
Task<Void> create(TEntity entity); | |
/** | |
* Updates an entity in the repository | |
* @param entity the new entity to be stored. | |
* @return A {@link Task} to be notified of failures. | |
*/ | |
Task<Void> update(TEntity entity); | |
/** | |
* Deletes an entity from the repository. | |
* @param id uniquely identifying the entity. | |
* @return A {@link Task} to be notified of failures. | |
*/ | |
Task<Void> delete(TKey id); | |
} |
Eusse.... If you're still dealing with the problem....
I had the same issue. Found out why. When you implement the identifiable interface, you need to also write the @exclude above @OverRide. If you don't, it tries to deal with that in the upload to firestore somehow, which apparently is not possible.
This is excellent !! Thanks :)
@NiPfi This is great!! One question though, how can I query by adding whereEqualTo and orderBy on get method?
Is there a reason these codes are written in Java instead of Kotlin?
@wonsuc There's a few but it basically boils down to this code being created for a school project during one semester and the school primarily teaching programming using Java. Also, when I wrote this code 2 years ago, Google was still in the process of making Kotlin the primary language for Android and since I don't program for Android professionally now, it didn't make sense to learn Kotlin for the purpose of a single semester.
@NiPfi Thanks for the answer, I just wondered if I can't use Repository
pattern with Kotlin for Firestore.
Can you post an example of the usage?
I created a data class that extends interface "Identifiable" and i get this error:
Found conflicting getters for name getEntityKey on class Model