Firebase Firestore : Document is not mapping to Model class - java

I was trying to build an app using Firebase Firestore but after retrieving the data on SnapshotListener it is not mapping to my model.
Here is My Model class
public class BlogPost {
private String description;
private String image;
private String user_id;
private String thumbnail_url;
private Timestamp timestamp;
public BlogPost() {
}
public BlogPost(String description, String image, String user_id, String thumbnail_url, Timestamp timestamp) {
this.description = description;
this.image = image;
this.user_id = user_id;
this.thumbnail_url = thumbnail_url;
this.timestamp = timestamp;
}
public String getImageUrl() {
return image;
}
public void setImageUrl(String image) {
this.image = image;
}
public String getUserId() {
return user_id;
}
public void setUserId(String user_id) {
this.user_id = user_id;
}
public String getThumbnailUrl() {
return thumbnail_url;
}
public void setThumbnailUrl(String thumbnail_url) {
this.thumbnail_url = thumbnail_url;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Timestamp getPostTime() {
return timestamp;
}
public void setPostTime(Timestamp timestamp) {
this.timestamp = timestamp;
}
}
To add data I am using this code:
firestore.collection("posts").addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
for (DocumentChange doc : queryDocumentSnapshots.getDocumentChanges()){
if (doc.getType() == DocumentChange.Type.ADDED){
BlogPost blogPost = doc.getDocument().toObject(BlogPost.class);
blogList.add(blogPost);`
blogRecyclerAdapter.notifyDataSetChanged();
}
}
}
});
Here is what I the object after mapping
BlogPost{description='post 6', image='null', user_id='null', thumbnail_url='null', timestamp=null}
Here is database structure screenshot
As you can see description mapped but all other fields are null.
Any help would be appreciated.

Two changes need to be done.
-> Make Every data member in your data class public
-> Annotate them with #PropertName()
public class BlogPost {
#PropertyName("description")
public String description;
#PropertyName("image")
public String image;
#PropertyName("user_id")
public String user_id;
#PropertyName("thumbnail_url")
public String thumbnail_url;
#PropertyName("timestamp")
public Timestamp timestamp;
}
try this.

Related

How do I deserialize a JSON representation containing array of objects using jackson?

I have the exact same JSON representation as here: https://newsapi.org/docs/endpoints/top-headlines
To deserialize this into java objects I have created a News and a Article class. News contains multiple Articles. So here are my classes:
News:
public class News {
private String status;
private int totalResults;
private Article[] articles;
public News() {
}
public News(String status, int totalResults, Article[] articles) {
this.status = status;
this.totalResults = totalResults;
this.articles = articles;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getTotalResults() {
return totalResults;
}
public void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
public Article[] getArticles() {
return articles;
}
public void setArticles(Article[] articles) {
this.articles = articles;
}
}
Article:
public class Article {
private String source;
private String author;
private String title;
private String description;
private String url;
private String imageUrl;
private String publishedAt;
private String content;
public Article() {
}
public Article(String source, String author, String title, String description, String url, String imageUrl,
String publishedAt, String content) {
this.source = source;
this.author = author;
this.title = title;
this.description = description;
this.url = url;
this.imageUrl = imageUrl;
this.publishedAt = publishedAt;
this.content = content;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getPublishedAt() {
return publishedAt;
}
public void setPublishedAt(String publishedAt) {
this.publishedAt = publishedAt;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
Now I am using the com.fasterxml.jackson.databind.ObjectMapper as following to deserialize the JSON representation into a News object:
ObjectMapper objectMapper = new ObjectMapper();
News news = objectMapper.readValue(response.toString(), News.class);
Here I am getting a com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
The problem apparently is the array of articles representated in JSON.
I have read about arrays deserialization in jackson but I found nothing about deserialization of objects that contain properties AND array of objects. https://www.baeldung.com/jackson-deserialization
How do I do this properly using the ObjectMapper? Am I missing out on something? Any help is appreciated, thanks!
Your source mapping is wrong,
the source field is of format
source": {
"id": "google-news",
"name": "Google News"
}
this can be replaced with
public class Source {
private String id;
private String name;
public Source() {}
public Source(String id, String name) {
this.id = id;
this.name = name;
}
}
and replace
private String source;
with
private Source source;
in the Article class

Firestore can't convert Document toObject

Im trying to retrieve a Document but I just can't get it to work. Here is my Code:
fm.getColRefProgramms().document(programmKey).collection("items").document("HIXQobZtlMxn4OblgOMi").get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
String s = documentSnapshot.getId();
OverviewItem item = documentSnapshot.toObject(OverviewItem.class);
item.setKey(item.getKey());
}
});
String s return the correct Id, so the Document is found and loaded from the Database but it canĀ“t create a OverviewIdem Object from it.
I get this error:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[])' on a null object reference
And this is the OverviewItem Class:
public class OverviewItem implements IProgrammItem, Serializable{
private String instance;
private String key;
private Programm programm;
private ArrayList<BasicElement> elements;
public OverviewItem() {}
public void setInstance(String instance) {
this.instance = instance;
}
public String getInstance() {
return instance;
}
#Exclude
public Programm getProgramm() {
return programm;
}
#Exclude
public String getKey() {
return key;
}
#Exclude
public void setKey(String key) {
this.key = key;
}
#Exclude
public void setProgramm(Programm programm) {
this.programm = programm;
}
public ArrayList<BasicElement> getElements() {
return elements;
}
public void setElements(ArrayList<BasicElement> elements) {
this.elements = elements;
}
}
And this is my Document:
FIX: I waited for half an hour, then it started to retrieve the data (Date's value was retrieved and wasn't null anymore). Maybe the database takes time to update, so give it some time (if you added a new value or document) and then check again.
I'm facing the same issue. This is my code:
firebasefirestore.collection("events").addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot documentSnapshots, #Nullable FirebaseFirestoreException e) {
for(DocumentChange doc: documentSnapshots.getDocumentChanges()){
if(doc.getType() == DocumentChange.Type.ADDED){
Map<String, Object> a = doc.getDocument().getData();
HomeViewModel event = doc.getDocument().toObject(HomeViewModel.class);
eventlist.add(event);
eventRecyclerAdapter.notifyDataSetChanged();
}
}
}
});
Here I created a variable 'a' to see the data, and the data is being successfully retrieved from Firestore (I was checking in the debugger).
Value of a
However when I use toObject(), Date is null.
My HomeViewModel class:
public class HomeViewModel{
private String Date;
private String Description;
private String Imagepath;
private String Title;
public void setDate(String date) {
this.Date = date;
}
public String getDate() {
return Date;
}
public String getImagepath() {
return Imagepath;
}
public void setImagepath(String imagepath) {
Imagepath = imagepath;
}
public void setDescription(String description) {
Description = description;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public String getTitle() {
return Title;
}
public HomeViewModel(){
}
public HomeViewModel(String title, String desc, String date, String imagepath) {
this.Title = title;
this.Description = desc;
this.Date = date;
this.Imagepath = imagepath;
}
}
Therefore it is clear that toObject is the problem.

retrofit 2.3.0 how to handle nested json?

I am kinda of new to retrofit and i am not sure how to handle a nested json structure like this. if any one can help how to parse this type of structure . i would really i appreciate it . i have been stuck for days
{
"status": "ok",
"totalResults": 20,
"articles": [
{
"source": {
"id": null,
"name": "Bradenton.com"
},
"author": "By EILEEN NG Associated Press",
"title": "Malaysia says search for missing plane to end in June",
"description": "An official says the search for Malaysia Airlines Flight 370 by a U.S. company will likely end in June, as families of passengers marked the fourth anniversary of the plane's disappearance with hope that the world's biggest aviation mystery will be solved.",
"url": "http://www.bradenton.com/news/business/article203286984.html",
"urlToImage": "http://www.mcclatchy-wires.com/incoming/ukogzw/picture203286949/alternates/LANDSCAPE_1140/Malaysia_Missing_Plane_57970.jpg",
"publishedAt": "2018-03-03T09:42:00Z"
}
]
}
the http://www.jsonschema2pojo.org/ to convert your json to POJO and use that for retrofit 2.3
If you don't know how many classes you need to make ,just copy and paste your json here click here.
This will help you and make your work easy.
Create some pojos:
class Source {
String id;
String name;
}
class Article{
Source source;
String author;
String title;
String description;
String url;
String urlToImage;
String publishedAt;
}
class GetArticlesResponse{
String status;
int totalResults;
List<Article> articles;
}
And then pass GetArticlesResponse to your retrofit call.
import retrofit2.Response;
import retrofit2.Call;
public interface YourInterface {
#GET("your_end_point")
Call<Response<GetArticlesResponse>> getArticles();
}
or if you're using RX:
import retrofit2.Response;
import rx.Observable;
public interface YourInterface {
#GET("your_end_point")
Observable<Response<GetArticlesResponse>> getArticles();
}
MainClass.java
public class MainClass {
#SerializedName("status")
#Expose
private String status;
#SerializedName("totalResults")
#Expose
private Integer totalResults;
#SerializedName("articles")
#Expose
private List<Article> articles = null;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getTotalResults() {
return totalResults;
}
public void setTotalResults(Integer totalResults) {
this.totalResults = totalResults;
}
public List<Article> getArticles() {
return articles;
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
}
Article.java
public class Article {
#SerializedName("source")
#Expose
private Source source;
#SerializedName("author")
#Expose
private String author;
#SerializedName("title")
#Expose
private String title;
#SerializedName("description")
#Expose
private String description;
#SerializedName("url")
#Expose
private String url;
#SerializedName("urlToImage")
#Expose
private String urlToImage;
#SerializedName("publishedAt")
#Expose
private String publishedAt;
public Source getSource() {
return source;
}
public void setSource(Source source) {
this.source = source;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrlToImage() {
return urlToImage;
}
public void setUrlToImage(String urlToImage) {
this.urlToImage = urlToImage;
}
public String getPublishedAt() {
return publishedAt;
}
public void setPublishedAt(String publishedAt) {
this.publishedAt = publishedAt;
}
}
Source.java
public class Source {
#SerializedName("id")
#Expose
private Object id;
#SerializedName("name")
#Expose
private String name;
public Object getId() {
return id;
}
public void setId(Object id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Retrofit Interface
public interface YourInterface {
#GET("whatever api u are using")
Call<MainClass> getData(#Query("whatever key") String/int(whatever name)) //or leave blank
}
well when working with retrofit i suggest using Gson library with it which parses your json to an object type you should have created so first you should create an object representing your object from the response you get so it will be something like this in your case
public class Article implements Serializable {
private String author;
private String title;
private String description;
private String url;
private String urlToImage;
private String publishedAt;
private Source source;
public Story() {
}
public Story(String author,
String title,
Source source,
String description,
String url,
String urlToImage,
String publishedAt) {
this.author = author;
this.title = title;
this.source = source;
this.url = url;
this.urlToImage = urlToImage;
this.publishedAt = publishedAt;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public double getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrlToImage() {
return urlToImage;
}
public void setUrlToImage(String urlToImage) {
this.urlToImage = urlToImage;
}
public String getPublishedAt() {
return publishedAt;
}
public void setPublishedAt(String publishedAt) {
this.publishedAt = publishedAt;
}
public Source getSource() {
return source;
}
public void setSource(Source source) {
this.source = source;
}
}
and similarly create your other class which is the Source class containing your Source object
public class Source implements Serializable {
private id id;
private String name;
public Source() {
}
public Source(int id,
String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
now in your retrofit api code you could do something like this
#GET("YOUR_ENDPOINT/")
Call<JsonObject> getArticles(... put your required fields here example ...#Query("token") String token);
and in your activity do something like this
List mArticleList = new ArrayList<>();
String mTotalResults = "";
UserApi service = ServiceGenerator.createService(UserApi.class);
Call<JsonObject> result = service.getArticles(token);
result.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if (response.code() == 200) {
mArticleList = null;
JsonArray data = response.body().getAsJsonObject("data").getAsJsonArray("articles");
mArticleList = new Gson().fromJson(data.toString(), new TypeToken<List<Article>>(){}.getType());
mTotalResults = response.body().getAsJsonObject("data").getAsString("totalResults");
//if you want it as an integer you could do something like
int totalResults = Integer.parseInt(mTotalResults);
//... do what you want with your list
//...
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
//do what you have to do in case of error
}
});
}
hope this helps

Duplicated attribute in Firebase

I have a model NewsFeedItem like this:
public class NewsFeedItem {
#PropertyName("like_number")
protected int likeCount = 0;
#PropertyName("time")
protected long timestamp;
#PropertyName("ownerUid")
protected String ownerUid;
#PropertyName("ownerUsername")
protected String ownerUsername;
#PropertyName("comments")
protected List<Comment> comments;
#PropertyName("likes")
protected Set<String> likes; //Store user uid of who like this status
public NewsFeedItem() {
}
protected NewsFeedItem(int likeCount, long timestamp, String ownerUid, String ownerUsername, List<Comment> comments, Set<String> likes) {
this.ownerUid = ownerUid;
this.ownerUsername = ownerUsername;
this.likeCount = likeCount;
this.timestamp = timestamp;
this.comments = comments;
this.likes = likes;
}
public int getLikeCount() {
return likeCount;
}
public void setLikeCount(int likeCount) {
this.likeCount = likeCount;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public String getOwnerUid() {
return ownerUid;
}
public void setOwnerUid(String ownerUid) {
this.ownerUid = ownerUid;
}
public String getOwnerUsername() {
return ownerUsername;
}
public void setOwnerUsername(String ownerUsername) {
this.ownerUsername = ownerUsername;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public Set<String> getLikes() {
return likes;
}
public void setLikes(Set<String> likes) {
this.likes = likes;
}
}
Then I subclass it in Status model:
#IgnoreExtraProperties
public class Status extends NewsFeedItem {
#PropertyName("content")
protected String content;
#PropertyName("photo")
protected String photoUrl;
public Status() {
//Required for deserialize
}
public Status(String ownerUid, String ownerUsername, String content, String photoUrl, int likeCount, long timestamp, List<Comment> comments, Set<String> likes) {
super(likeCount, timestamp, ownerUid, ownerUsername, comments, likes);
this.content = content;
this.photoUrl = photoUrl;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getPhotoUrl() {
return photoUrl;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
}
}
The code pushing data to Firebase:
#Override
public void pushStatusToFirebase(Status status) {
database.getReference("status").push().setValue(status);
}
But when I push to Firebase the like_number and likeCount display together like this:
It also happen to all of my model class. Please help me.
To solve this, you need to make all your fields public and not protected as they are now, otherwise the annotations will not work.
Now, the annotation takes into account both the field name as well as the getter/setter names to serialize. You have this problem because the fields as well as the getter/setters were getting serialized and that's why are resulting duplicates.
So use the annotation on the field name which are public and ignore the getter/setters. This will solve your problem. Your data will be properly serialized with the property name you want and there will be no duplicates as well.
Try to mark with #PropertyName your getters instead of fields. Another option that may be working - mark with #Exclude your getters.

How to add a mongo id from one collection as a foreign key in another collection

In my Spring boot application, I have collection of Todos and a collection of Courses. In the view of the application, I return the collection of courses and display whatever course I need. The Todos are stored as 1 list which represents all the current Todos. What I would like to do is return a list of Todos for each course. So when the view is opened, the application would display the the course plus the individual todo list for that course.
Is there a way I can use the existing code to incorporate the new functionality. I have created the front end logic and would like to keep that. My initial idea was to add the the course id to the Todo.java, but that did not work.
Todo.java
#Document(collection="todos")
public class Todo {
#Id
private String id;
#NotBlank
#Size(max=250)
#Indexed(unique=true)
private String title;
private Boolean completed = false;
private Date createdAt = new Date();
public Todo() {
super();
}
public Todo(String title) {
this.title = title;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Boolean getCompleted() {
return completed;
}
public void setCompleted(Boolean completed) {
this.completed = completed;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
#Override
public String toString() {
return String.format(
"Todo[id=%s, title='%s', completed='%s']",
id, title, completed);
}
}
TodoRepository.java
#Repository
public interface TodoRepository extends MongoRepository<Todo, String> {
public List<Todo> findAll();
public Todo findOne(String id);
public Todo save(Todo todo);
public void delete(Todo todo);
}
Courses
#Document(collection = "courses")
public class Courses {
#Id
private String id;
private String name;
private String lecturer;
private String picture;
private String video;
private String description;
private String enroled;
public Courses(){}
public Courses(String name, String lecturer, String picture, String video, String description,String enroled) {
this.name = name;
this.lecturer = lecturer;
this.picture = picture;
this.video = video;
this.description = description;
this.enroled = enroled;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLecturer() {
return lecturer;
}
public void setLecturer(String lecturer) {
this.lecturer = lecturer;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getVideo() {
return video;
}
public void setVideo(String video) {
this.video = video;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getEnroled() {
return enroled;
}
public void setEnroled(String enroled) {
this.enroled = enroled;
}
#Override
public String toString() {
return "Courses{" +
"id='" + id + "'" +
", name='" + name + "'" +
", lecturer='" + lecturer + "'" +
", description='" + description + "'" +
'}';
}
}

Categories