Save object with BackendlessUser relations

Hi guys,
I’m getting the following error while trying to save an Event object that has a List of BackendlessUser inside of it.
Here is my Event class:

public class Event {
    private String objectId;
    private String ownerId;
    private String name;
    private List<BackendlessUser> users;
    ...
}

Code where I call the saving function:

BackendlessUser user = Backendless.UserService.CurrentUser();
Event e = new Event(name, description, location, user);
Backendless.Persistence.of(Event.class).save(e, new AsyncCallback<Event>() {...}

The error I’m getting is not captured by the Handling function:

D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: Process: br.edu.ufcg.kickabout, PID: 16731
E/AndroidRuntime: java.lang.ClassCastException: java.util.HashMap[] cannot be cast to java.util.Collection
E/AndroidRuntime:     at com.backendless.FootprintsManager$Inner.duplicateFootprintForObject(FootprintsManager.java:178)
E/AndroidRuntime:     at com.backendless.FootprintsManager$Inner.duplicateFootprintForObject(FootprintsManager.java:191)
E/AndroidRuntime:     at com.backendless.Persistence$3.handleResponse(Persistence.java:162)
E/AndroidRuntime:     at com.backendless.async.message.AsyncMessage$ResponseHandler.handle(AsyncMessage.java:64)
E/AndroidRuntime:     at com.backendless.async.message.AsyncMessage.handleCallback(AsyncMessage.java:41)
E/AndroidRuntime:     at com.backendless.core.AndroidCarrier$1.handleMessage(AndroidCarrier.java:37)
E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:98)
E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:145)
E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:6843)
E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

Am I doing anything wrong?

Thanks in advance.

Hi Jordao,

Could you please attach a complete listing of the Event class?

Regards,
Mark

Hi Mark,

The Event class is attached.
Inside of my constructor, if I add a BackendlessUser to my list of users before saving the Event, it will break.
If I don’t insert the user I can save the Event normally.

Event.txt (1.65kB)

Hi Jordao,

I just tried saving an object (with related user) and it works for me. Could you please make sure you’re using the latest build which you can download from here:

Regards,
Mark

Hi Mark,

I’m using the following in my gradle dependencies:

 'com.backendless:backendless:3.0.8.2' 

Let me explain it better…
I’m trying to create a relation NtoN. For that, I created a relation 1toN in Event and a relation 1toN in Users.
Event has a list of BackendlessUser and Users has a list of Event.
When I create an Event and save it with his list of BackendlessUsers, it works fine.
Inside the same handle function, now I add that event (that now has an objectId) to the events list in Users.
When I try to update my current user, it breaks giving me that error before mentioned.
In the server side, the event is saved, but the relation User->Event is not saved.
Also, sometimes I’ve noticed that, if the Event’s table is empty, it works fine for both, but if Event’s table has at least 1 element, it does’n seem to work.

Event currentEvent;
BackendlessUser user = Backendless.UserService.CurrentUser();
Event e = new Event(name, description, location, user);
Backendless.Persistence.of(Event.class).save(e, new AsyncCallback<Event>() {
    @Override
    public void handleResponse(Event response) {
        currentEvent = response;
        BackendlessDataQuery query = new BackendlessDataQuery();
        query.setWhereClause("Users[events].objectId = '" + user.getObjectId() + "'");
        Backendless.Data.of(Event.class).find(query, new AsyncCallback<BackendlessCollection<Event>>() {
            @Override
            public void handleResponse(BackendlessCollection<Event> response) {
                List<Event> list = new ArrayList<Event>();
                for (Event evt : response.getData()) {
                    list.add(evt);
                }
                list.add(currentEvent);
                user.setProperty("events", list);
                Backendless.UserService.update(user, new AsyncCallback<BackendlessUser>() {
                    @Override
                    public void handleResponse(BackendlessUser response) {
                        Backendless.UserService.setCurrentUser(response);
                        setResult(RESULT_OK);
                        finish();
                    }
                    @Override
                     public void handleFault(BackendlessFault fault) {
                         Log.wtf(TAG, fault.getMessage());
                     }
                });
                }
                @Override
                public void handleFault(BackendlessFault fault) {
                   Log.wtf(TAG, fault.getMessage());
                }
            });
            }
        });
    }
    @Override
    public void handleFault(BackendlessFault fault) {
        Log.wtf(TAG, fault.getMessage());
    }
});

The code seems to be a mess… Does it compile for you?

It seems to be a mess because the tag code here does it to every code we post. It does compile for me.

But you don’t need to look at the code to understand what I said. I’m trying to create a relation N to N.
Could you please simulate a relation N to N using BackendlessUser table and other table that has relation to it. Also, if you could attach the code I would really appreciate (that way I can understand how you guys work with it).

thanks

I understand what you said, I wanted to run the same code to see if I can reproduce the problem. Could you post the code to something like http://pastie.org/ and post a link here?

I’ve recreated a cleaner project only with two classes. The Event entity and the MainActivity.
Event: http://pastie.org/10759456

MainActivity: http://pastie.org/10759460

I’ve even written my app credentials (app id and secret key) in MainActivity in case you need them. The user being used is still there in Backendless server.
The problem seems to occur when I try to get user properties as a list of Events and add a new Event. Also, in this new example the problem is occurring only when I have at least one Event already saved in Backendless server.

I ran the code you provided and didn’t get any errors (I am using the latest build from github). Here’s the Event table with the data:
http://support.backendless.com/public/attachments/643a1f849ba814091cbe3ad643f84fd2.jpg</img>

I was using gradle to get the lastest sdk build.
I just downloaded the .jar file from here: https://github.com/Backendless/Android-SDK/tree/master/out , but I can’t add it to my project. It has only 48KB while the one that I get from gradle has more than 100KB.
Is this file corrupted?

Error:error reading F:\...\app\lib\backendless.jar; error in opening zip file connection timeout.)
<a href="syncProject">Re-download dependencies and sync project (requires network)</a>

Am I getting the right file?

The file in github is 931kb:

http://support.backendless.com/public/attachments/a8b5ccda7d7d1fba9d0fa956b99eba1a.jpg</img>

Hi Mark,

Thanks for all your help.
My connection probably had any kind of problem while downloading the file (the size was really weird).
The problem was not in the .jar though. Even compiling with the gradle .jar I don’t have problems anymore.
The problem was that I was updating the current user Backendless.UserService.setCurrentUser() with the user returned from method update (Backendless.UserService.update()). The response User.

 Backendless.UserService.update(user, new AsyncCallback&lt;BackendlessUser&gt;() {
 @Override
 public void handleResponse(BackendlessUser response) {
  Backendless.UserService.setCurrentUser(response);
 }
 @Override
 public void handleFault(BackendlessFault fault) {
 Log.e("ERROR", fault.getMessage());
 }
 });

It seems to not work. As soon as I requested the user again to the server, the problem was solved.

Backendless.UserService.update(user, new AsyncCallback&lt;BackendlessUser&gt;() {
 @Override
 public void handleResponse(BackendlessUser response) {
  Backendless.UserService.findById(response.getObjectId(), new AsyncCallback&lt;BackendlessUser&gt;() {
 @Override
 public void handleResponse(BackendlessUser backendlessUser) {
 Backendless.UserService.setCurrentUser(backendlessUser);
 }
 
 
 



 @Override
 public void handleFault(BackendlessFault backendlessFault) {
 }
 });
 }
 @Override
 public void handleFault(BackendlessFault fault) {
 Log.e("ERROR", fault.getMessage());
 }
});

Seems kinda weird to me, because the response would be updated, don’t you think?

Anyway… Thanks for your help again.

Best Regards,
Jordao Serafim

The primary difference between this request:

Backendless.UserService.update(user, new AsyncCallback&lt;BackendlessUser&gt;() {
@Override
public void handleResponse(BackendlessUser response) {
}

and this one:

Backendless.UserService.findById(response.getObjectId(), new AsyncCallback&lt;BackendlessUser&gt;() {
@Override
public void handleResponse(BackendlessUser backendlessUser) {
}

is that in the first one any auto-load properties are NOT returned (because it is an update request). With all “find” operation, auto-load properties are returned.

Does the problem happen after you (1) call update, (2) set current user and then (3) save the user object?

Regards,
Mark

You mean… save the Event Object? Or save the user using something like this:

Backendless.Data.of(BackendlessUser.class).save(user);

Because we don’t have a save method in Backendless.UserService. We only have update.
If it’s for saving Events on the third step, I think the problem is still occurring.
The problem was that I needed some properties in User that had to be auto loaded, but as you mentioned the update method doesn’t do that.

Regards,
Jordao

No, I didn’t mean saving an event object.

Look at the code you posted. You said the following code does not work:

Backendless.UserService.update(user, new AsyncCallback&lt;BackendlessUser&gt;() {
@Override
public void handleResponse(BackendlessUser response) {
Backendless.UserService.setCurrentUser(response);
}
@Override
public void handleFault(BackendlessFault fault) {
Log.e("ERROR", fault.getMessage());
}
});

The reason is does not work is: You call “Backendless.UserService.update(user”, which sends user object to the server with the relations it has and performs update. The response for that operation returns updated user object for which you do this:

Backendless.UserService.setCurrentUser(backendlessUser);

It is important to keep it mind that the user object you received back from the update operation, does not contain initialized related objects. As a result, when you set that user object as current, it will not have events.

Things are different in the code that you described as “working”:

Backendless.UserService.update(user, new AsyncCallback&lt;BackendlessUser&gt;() {
@Override
public void handleResponse(BackendlessUser response) {
Backendless.UserService.findById(response.getObjectId(), new AsyncCallback&lt;BackendlessUser&gt;() {
@Override
public void handleResponse(BackendlessUser backendlessUser) {
Backendless.UserService.setCurrentUser(backendlessUser);
}

What you have here is this:

  1. Update user object on the server
  2. In the response retrieve user object from the server
  3. in the response for (2) you set the user as the current object.

Here’s why it is working: the user object you receive from (1) does not contain related objects. The user object you receive from (2) CONTAINS related objects. So when you set the current user to the one you received from (2), it is in the state that your program expects (meaning it has relations).

Mark