getting zero objects from BackendlessUser getProperty() - java

I've setup Backendless app, with User table having row name posts, which is data object relationship between User and Post tables, data relation is 1 to many. When I try to retrieve it using BackendlessUser.getProperty("key"), it returns zero objects. Once it even returned HashMap. I used the way mentioned in the the docs, but get null because the size of the Object[] is zero. I have data in that row for sure, wrote <uses-permission> for internet.
public class MainActivity extends AppCompatActivity {
BackendlessUser user = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Backendless.initApp(this, "app_id", "android_key", "v1");
Backendless.UserService.login("username", "password", new AsyncCallback<BackendlessUser>() {
#Override
public void handleResponse(BackendlessUser response) {
user = response;
doStuff();
}
#Override
public void handleFault(BackendlessFault fault) {
Log.e("Error logging in", "message: " + fault.getMessage());
}
});
}
//important
private void doStuff() {
Object[] postObjectArray = (Object[]) user.getProperty("posts");
Post[] posts = null;
if (postObjectArray != null && postObjectArray.length > 0)
posts = (Post[])postObjectArray;
if (posts == null)
{
Log.d("Problems", "posts is null");
}
}
}
Post class:
public class Post extends Object{
private BackendlessUser user;
private String file;
private String message;
private String objectId;
public String getObjectId() {
return objectId;
}
public void setObjectId(String objectId) {
this.objectId = objectId;
}
public Post() {
}
public Post(BackendlessUser user, String file, String message) {
this.user = user;
this.file = file;
this.message = message;
}
public BackendlessUser getUser() {
return user;
}
public void setUser(BackendlessUser user) {
this.user = user;
}
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

The reason was that checkbox "autoload", which loads all values of one to many relationships to which checkbox corresponds when the owning table was loaded, wasn't checked. Thus, user.getProperty("posts") was always returning null. But it should be noted that if the row is data object relationship, it returns HashMap<String, Object>, so Post needs to have constructor which accepts HashMap<String, Object>:
public Post(HashMap hashMap)
{
this.hashMap = hashMap;
property1 = (String)hashMap.get("property1");
/*other properties*/
}
If there is no values, it will return an Object, which is not castable to any other type, so the way used in the docs must be applied in order to fix edge cases.
EDIT:
It's useful to map data table to class before making any calls to Backendless. That way, it is possible to eliminate all work with HashMap and directly get desired type. Despite that, if you're retrieving data through Backendless.Persistence you can specify it as argument.

Related

How to get access to a HashMap of objects from the Objects in that HashMap. (Java)

I have a hash map of some POJO Objects of a Class named User: HashMap<ObjectId, User>
These objects (Users) are related to each other. (I need to search through other users to Update one's Parameters)
How can I have access to the HashMap within a user object?
import org.bson.types.ObjectId;
import org.bson.BsonDocument;
import java.util.ArrayList;
import java.util.List;
public class User {
private ObjectId _id;
private int grade;
private String region;
private ArrayList<ObjectId> _reg_by;
private ObjectId regBy;
public User(){
}
public ObjectId getId() {
return _id;
}
public void setId(final ObjectId id) {
this._id = id;
}
public int getGrade() {
return grade;
}
public void setGrade(final int grade) {
this.grade = grade;
}
public String getRegion() {
return region;
}
public void setRegion(final String region) {
this.region = region;
}
public ObjectId getRegBy() {
if(regBy == null) {
regBy = ((_reg_by.size() != 0) ? _reg_by.get(0) : null);
}
return regBy;
}
public void setRegBy(final ObjectId regBy) {
this.regBy = regBy;
}
public ArrayList<ObjectId> get_reg_by(){
return _reg_by;
}
public void set_reg_by(ArrayList<ObjectId> _reg_by){
this._reg_by = _reg_by;
}
private String updateRegion(){
if(getRegBy() == null)
return null;
//TODO search for the person who registered him and use the region!
// how to get access to others from here?!
}
}
This is the User class where in regionUpdate() function I want to have this access
I creat this HashMap in my Main function.
HashMap<ObjectId, User> users = mongoHandler.getUsers();
I solved my problem by defining my HashMap as Static.
public static HashMap<ObjectId, User> users
so I can easily have access to it from anywhere by using the following code:
HashMap<ObjectId, User> users = Main.users
or any method e.g. Main.users.getId();
Another solution could have been to create a property within your "User" class that contains a list of related users, and if you know that one user is related to another, added it to the each user as you build the list.
public class User {
...
private List<User> relatedUsers = new ArrayList<User>();
...
private void updateRelatedUsers() {
for(User relatedUser : relatedUsers) {
//do stuff to update the relatedUser object.
relatedUser.setSomething(someValue);
}
}
//Getter and setter
public List<User> getRelatedUsers() {
return relatedUsers;
}
public void setRelatedUsers(List<User> relatedUsers) {
this.relatedUsers = relatedUsers;
}
...
}
Add the users like so:
...
User myUser = creatUserHoweverYouDo();
User myRelatedUser = getMyRelatedUser(myUser);
myUser.getRelatedUsers().add(myRelatedUser);
...

Room #Insert does not insert all records

I am running into an issue where only 1 record is being inserted into my Room SQLite DB.
When I perform a getAll(); the result only returns 1 record.
FOUND ISSUE: Genre[] genres = gson.fromJson(jsonArray.toString(), Genre[].class);
This line above is setting all "gid" values to 0, and I am not sure how to change that.
Genre.java
#Entity(indices = {#Index(value = {"id", "name"}, unique = true)})
public class Genre {
#PrimaryKey
private int gid;
//#ColumnInfo(name = "id") By Default - No need to annotate
#NonNull
private int id;
private String name;
public int getGid() {
return gid;
}
public void setGid(int gid) {
this.gid = gid;
}
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;
}
}
GenreDao.java
#Dao
public interface GenreDao {
#Query("SELECT * FROM Genre")
LiveData<List<Genre>> getAll();
#Insert(onConflict = OnConflictStrategy.REPLACE) //If there is a conflict, replace the record.
void insertAll(Genre... genres);
}
GenreRepository.java
public class GenreRepository {
private final GenreDao genreDao;
public GenreRepository(GenreDao genreDao) {
this.genreDao = genreDao;
}
//Database Methods
public void insertAll(Genre... genres) {
AsyncTask.execute(() -> { //Same as new Runnable()
genreDao.insertAll(genres);
});
}
public LiveData<List<Genre>> getAll() {
return genreDao.getAll();
}
}
APIUtil.java - getGenres() Method
This class makes an API call, returns the proper results, converts the JSONArray to a Genre[]. I can successfully loop through the Genre[] and confirm 10+ results come back.
public static void getGenres(Context context) {
APIWrapper wrapper = new APIWrapper(context, API_KEY);
Parameters params = new Parameters();
params.addFields(GENRE_FIELDS);
params.addLimit("50");
wrapper.genres(params, new onSuccessCallback() {
#Override
public void onSuccess(JSONArray jsonArray) {
Gson gson = new Gson();
Genre[] genres = gson.fromJson(jsonArray.toString(), Genre[].class);
//Insert DB
AppDatabase db = AppDatabase.getAppDatabase(context);
GenreRepository genreRepository = new GenreRepository(db.genreDao());
genreRepository.insertAll(genres);
}
#Override
public void onError(VolleyError volleyError) {
Log.e("GENRES ERROR:", volleyError.toString());
}
});
}
GenreViewModel.java
public class GenreViewModel extends ViewModel {
private GenreRepository genreRepository;
public GenreViewModel(GenreRepository genreRepository) {
this.genreRepository = genreRepository;
}
public void insertAll(Genre... genres){
genreRepository.insertAll(genres);
}
public LiveData<List<Genre>> getAll(){
return genreRepository.getAll();
}
}
SearchFragment.java
This is where I am retrieving the database values. This for loop only returns 1 result.
AppDatabase db = AppDatabase.getAppDatabase(getActivity());
GenreRepository genreRepository = new GenreRepository(db.genreDao());
GenreViewModel genreViewModel = new GenreViewModel(genreRepository);
genreViewModel.getAll().observe(this, genres -> { //new Observer<List<Genre>>()
for(Genre g : genres){
Log.e("GENRE", g.getName());
}
});
public void insertAll(Genre... genres){
genreRepository.insertAll(genres);
}
here is your mistake , what you provide as method definition and what you provide at call. see you make some thing wrong.
Solution
void insertAll(List<T> obj);
you can try with convert your array to list and put above in definition
I had this problem too.
And Solved it this way.
The problem was that the id that comes from server was mongoId and String so I should create a int primary key and pass currentTime as value to it so the database can insert all of them not replace them.
But you should consider using System.nanoTime() method instead of System.currentTimeMillis() cause sometimes it generates same value and then room replace them instead of inserting each one of them.

Using AsyncTask in Activity fails

I have an application in which I wanted to store a list of items and I figured a database would do. I found out about the new Room API and tried using it, though I'm having some trouble getting it working. I have a background service which is supposed to write entries to the database. I read that using the singleton pattern was recomended, but I can't seem to get it working. When I try to retrieve all entries in my MainActivity, the list I get back is always empty, indicating that I wasn't able to save them from the start.
Singleton db class
#Database(entities = {TemperatureReading.class}, version = 1)
public abstract class DatabaseSingleton extends RoomDatabase {
private static DatabaseSingleton INSTANCE;
public abstract TemperatureReadingDao temperatureReadingDao();
public static DatabaseSingleton getAppDatabase(Context context) {
if (INSTANCE == null) {
INSTANCE =
Room.databaseBuilder(context.getApplicationContext(), DatabaseSingleton.class, "fireTempDatabase")
.build();
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
}
Entity
#Entity
public class TemperatureReading {
#PrimaryKey(autoGenerate = true)
private int uid;
#ColumnInfo(name = "dateTime")
private long dateTime;
#ColumnInfo(name = "location")
private String readingLocation;
#ColumnInfo(name = "value")
private float value;
public long getDateTime() {
return dateTime;
}
public void setDateTime(long dateTime) {
this.dateTime = dateTime;
}
public String getReadingLocation() {
return readingLocation;
}
public void setReadingLocation(String readingLocation) {
this.readingLocation = readingLocation;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
}
EntityDAO
#Dao
public interface TemperatureReadingDao {
#Query("SELECT * FROM temperatureReading")
List<TemperatureReading> getAll();
#Query("SELECT * FROM temperatureReading ORDER BY uid desc limit 1")
TemperatureReading getLatest();
#Insert
void insertAll(TemperatureReading... temperatureReading);
#Update
void update(TemperatureReading... temperatureReading);
#Delete
void delete(TemperatureReading temperatureReading);
}
Background service which saves to db
private void saveTempDatabase(float tmpMessageAsFloat, long tmpMessageDateTime) {
Log.d(TAG, "saveTempDatabase");
TemperatureReading tr = new TemperatureReading();
tr.setDateTime(tmpMessageDateTime);
tr.setReadingLocation("XXX"); //TODO
tr.setValue(tmpMessageAsFloat);
DatabaseSingleton.getAppDatabase(getApplicationContext()).temperatureReadingDao().insertAll(tr);
}
MainActivity were db is read from, uses Async task so it doesn't block UI
private void updateTemperature() {
Log.d(TAG, "updateTemperature");
new AsyncTask<Void, Void, Integer>() {
#Override
protected Integer doInBackground(Void... params) {
List<TemperatureReading> tr = DatabaseSingleton.getAppDatabase(MainActivity.this).temperatureReadingDao().getAll(); //List is always empty, no matter how many times I have called the saveTempDatabase() method in the service class.
return 0;
}
#Override
protected void onPostExecute(Integer agentsCount) {
}
}.execute();
}
Maybe it has to do with the context somehow?
EDIT:
Just tried adding .allowMainThreadQueries() when building the database and now it works. So for some reason my Async task isn't working?
Your AsyncTask seems to be wrong. You should return the list you would like to handle in doInBackground and then expect it in onPostExecute. Why do you always return 0?

How to solve StringConverter ClassCast Exception?

I have a TableView and a form with some TextBox and ComboBox in my javafx application. I am trying to populate the form components with selected rows data from TableView. I can populate all the TextBox without any error or exception. But while setting values to ComboBoxes, it's throwing an ClassCastException, java.lang.ClassCastException: java.lang.String cannot be cast to entity.StockUOM.
This is my StringCoverter
unitCombo.setConverter(new StringConverter<StockUOM>() {
#Override
public String toString(StockUOM object) {
return object.getStockUOM();
}
#Override
public StockUOM fromString(String string) {
return null;
}
});
This is my entity.StockUOM class
#Entity
#Access(AccessType.PROPERTY)
#NamedQueries({
#NamedQuery(name = StockUOM.findStockUOM, query = "SELECT s from StockUOM s")
})
public class StockUOM implements Externalizable{
public final static String PREFIX = "entity.StockUOM.";
public final static String findStockUOM = PREFIX + "findStockUOM";
private IntegerProperty id;
private int _id;
private StringProperty stockUOM;
private String _stockUOM;
public StockUOM() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id", _id);
}
if( stockUOM== null){
stockUOM= new SimpleStringProperty(this,"stockUOM",_stockUOM);
}
}
public StockUOM(String stockUOM) {
this();
this.stockUOM.set(stockUOM);
}
public IntegerProperty idProperty() {
if (id == null) {
id = new SimpleIntegerProperty(this, "id", _id);;
}
return id;
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public final int getId() {
if (id == null) {
return _id;
} else {
return id.get();
}
}
public final void setId(int id) {
if (this.id == null) {
_id = id;
} else {
this.id.set(id);
}
}
public StringProperty stockUOMProperty() {
if( stockUOM== null){
stockUOM= new SimpleStringProperty(this,"stockUOM",_stockUOM);
}
return stockUOM;
}
public final String getStockUOM() {
if(stockUOM == null){
return _stockUOM;
}else{
return stockUOM.get();
}
}
public void setStockUOM(String stockUOM) {
if (this.stockUOM == null) {
_stockUOM=stockUOM ;
} else {
this.stockUOM.set(stockUOM);
}
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(getId());
out.writeChars(getStockUOM());
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
setId(in.readInt());
setStockUOM((String)in.readObject());
}
#Override
public String toString() {
return getStockUOM();
}
}
This is how i am setting values to ComboBox
unitCombo.setValue(newValue.getUnit());
Here newValue is the instance of StockUOM of ChangeListner which is listening on TableView row selection.
So what's wrong i am doing ? And what's the solution.
Thanks.
The problem is that most probably you defined your ComboBox like:
ComboBox unitCombo = new ComboBox();
So you missed to define the generic argument and you ended up with the raw type (your IDE most probably gives you a warning on this line).
At this point it is not specified what kind of objects do you want to display in the ComboBox.
When you do the following:
unitCombo.setValue(newValue.getUnit());
you set the valueProperty as a String value.
And then comes your converter:
unitCombo.setConverter(new StringConverter<StockUOM>() {
#Override
public String toString(StockUOM object) {
return object.getStockUOM();
}
#Override
public StockUOM fromString(String string) {
return null;
}
});
which expects StockUOM object being displayed, which does not happen hence the error.
You have to decide what kind of object do you want to display: if it is StockUOM, then declare the ComboBox as ComboBox<StockUOM> unitCombo = new ComboBox<StockUOM>();. After this you will have a compile time error on the line where you set the value for a String value, to fix that error you have to modify that line as unitCombo.setValue(newValue);. If you want to display String objects, the methodology is the same.

AzureMobileService: Insert data in to table gives exception

I am new to implement Azure Mobile Service. I have refer the demo of ToDoItem given by Azure.
In same manner i have make class User for my own app. Then I am inserting the data in to the MobileServiceTable but it gives me error like below:
{"message":"The operation failed with the following error: 'A null store-generated value was returned for a non-nullable member 'CreatedAt' of type 'CrazyLabApp.Models.User'.'."}
I have not created any field like this as it is not created in ToDoItem demo as well. I have seen that there are 4 fields that are by Default created by the MobileServiceTable. createdAt is one of the field of that.
I am wonder about whats wrong i am doing.
Check my below Userclass:
public class User {
#com.google.gson.annotations.SerializedName("id")
private String ServiceUserId;
#com.google.gson.annotations.SerializedName("email")
private String Email;
#com.google.gson.annotations.SerializedName("firstname")
private String FirstName;
#com.google.gson.annotations.SerializedName("lastname")
private String LastName;
#com.google.gson.annotations.SerializedName("profilepic")
private String ProfilePic;
#com.google.gson.annotations.SerializedName("introduction")
private String Introduction;
#com.google.gson.annotations.SerializedName("website")
private String Website;
#com.google.gson.annotations.SerializedName("title")
private String Title;
#com.google.gson.annotations.SerializedName("_createdAt")
private Date CreatedAt;
#com.google.gson.annotations.SerializedName("coverimage")
private ArrayList<CoverImage> CoverImages;
/*public Date getCreatedAt() {
return CreatedAt;
}
public void setCreatedAt(Date createdAt) {
CreatedAt = createdAt;
}*/
#com.google.gson.annotations.SerializedName("followers")
private ArrayList<User> Followers;
#com.google.gson.annotations.SerializedName("likes")
private ArrayList<Likes> Likes;
#com.google.gson.annotations.SerializedName("collections")
private ArrayList<Collections> Collections;
#com.google.gson.annotations.SerializedName("comments")
private ArrayList<Comments> Comments;
#com.google.gson.annotations.SerializedName("stories")
private ArrayList<Story> Stories ;
//-------------- Methods
public ArrayList<Story> getStories() {
return Stories;
}
public void setStories(ArrayList<Story> stories) {
Stories = stories;
}
public ArrayList<com.promact.crazylab.model.Comments> getComments() {
return Comments;
}
public void setComments(ArrayList<com.promact.crazylab.model.Comments> comments) {
Comments = comments;
}
public ArrayList<com.promact.crazylab.model.Collections> getCollections() {
return Collections;
}
public void setCollections(ArrayList<com.promact.crazylab.model.Collections> collections) {
Collections = collections;
}
public ArrayList<com.promact.crazylab.model.Likes> getLikes() {
return Likes;
}
public void setLikes(ArrayList<com.promact.crazylab.model.Likes> likes) {
Likes = likes;
}
public ArrayList<User> getFollowers() {
return Followers;
}
public void setFollowers(ArrayList<User> followers) {
Followers = followers;
}
public ArrayList<CoverImage> getCoverImages() {
return CoverImages;
}
public void setCoverImages(ArrayList<CoverImage> coverImages) {
CoverImages = coverImages;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getWebsite() {
return Website;
}
public void setWebsite(String website) {
Website = website;
}
public String getIntroduction() {
return Introduction;
}
public void setIntroduction(String introduction) {
Introduction = introduction;
}
public String getLastName() {
return LastName;
}
public void setLastName(String lastName) {
LastName = lastName;
}
public String getProfilePic() {
return ProfilePic;
}
public void setProfilePic(String profilePic) {
ProfilePic = profilePic;
}
public String getEmail() {
return Email;
}
public void setEmail(String email) {
Email = email;
}
public String getFirstName() {
return FirstName;
}
public void setFirstName(String firstName) {
FirstName = firstName;
}
public String getServiceUserId() {
return ServiceUserId;
}
public void setServiceUserId(String serviceUserId) {
ServiceUserId = serviceUserId;
}
#Override
public boolean equals(Object o) {
return o instanceof User && ((User) o).ServiceUserId == ServiceUserId;
}
}
Also check below code the way i am inserting it:
final User u = new User();
u.setFirstName(mName);
u.setEmail(mEmail);
u.setProfilePic(mUrl);
mUserTable = mClient.getTable(User.class);
// Insert the new item
new AsyncTask<Void, Void, Void>(){
#Override
protected Void doInBackground(Void... params) {
try {
final User entity = mUserTable.insert(u).get();
} catch (Exception e){
//createAndShowDialog(e, "Error");
System.out.println("Error: "+e.toString());
}
return null;
}
}.execute();
Please help me in this.
The "_createdat" column will be populated automatically by Azure Mobile Services so there is no need to include it in your model. Delete this property from the User class. Its presence is probably overwriting the auto-populated value with a null.
you can solve this problem by just deleting createdAt column from your user table in azure.
Why this error is coming :
I am not sure But I guess this error is coming because createdAt is a non-nullable member and you cannot left it null.
EDIT :
Another aspect of the system columns is that they cannot be sent by the client. For new tables (i.e., those with string ids), if an insert of update request contains a property which starts with ‘__’ (two underscore characters), the request will be rejected. The ‘__createdAt’ property can, however, be set in the server script (although if you really don’t want that column to represent the creation time of the object, you may want to use another column for that) – one way where this (rather bizarre) scenario can be accomplished. If you try to update the ‘__updatedAt’ property, it won’t fail, but by default that column is updated by a SQL trigger, so any updates you make to it will be overridden anyway.
for more info take a look here :-http://blogs.msdn.com/b/carlosfigueira/archive/2013/11/23/new-tables-in-azure-mobile-services-string-id-system-properties-and-optimistic-concurrency.aspx

Categories