简体   繁体   中英

How do I correctly save a google user in google datastore using objectify?

I try to store a Google User (com.google.appengine.api.users.User) inside of an own class in google datastore using objectify. I am using objectify (com.googlecode.objectify) version 5.0.3 and (com.sappenin.objectify) version 5.0.2. This is my class:

@Entity
public class UserTest {
    @Id
    public Long id;
    @Index
    public User user;
    public UserTest() {}
    public UserTest(User user) {
        super();
        this.user = user;
    }
}

Now I try to store an object of this class using the following servlet class:

import static OfyService.ofy;
@Path("/userStore")
public class UserStoreTestService {
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public User saveUser() {
        Key<UserTest> key = ofy().save().entity(new UserTest(getUser())).now();
        UserTest userTest = ofy().load().key(key).now();
        return userTest.user;
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public User loadUser() {
        UserTest userTest = ofy().load().type(UserTest.class)
            .filter("user", getUser()).first().now();
        return userTest.user;
    }

    private User getUser() {
        return UserServiceFactory.getUserService().getCurrentUser();
    }
}

My ofy service looks like that:

import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyFactory;
import com.googlecode.objectify.ObjectifyService;
public class OfyService {
    static {
        factory().register(UserTest.class);
    }
    public static Objectify ofy() {
        return ObjectifyService.ofy();
    }
}

When I do a POST request i get this JSON code:

{"email":"test@example.com","authDomain":"gmail.com","userId":"18580476422013912411","federatedIdentity":null,"nickname":"test@example.com"}

When I do a GET request after the POST I get this JSON code:

{"email":"test@example.com","authDomain":"gmail.com","userId":"-1405876145","federatedIdentity":null,"nickname":"test@example.com"}

The first Id is 18580476422013912411 the second one is -1405876145 .

What am I doing wrong?

According to this question , App Engine's datastore can store numbers up to 9,223,372,036,854,775,807 (unsigned long limit). The userId is bigger, hence your issue.

You should store your userId in a String. Anyway, you will not perform any numeric operation on it I assume (comparison, addition, division...).

Here a quick workaround would be to store the userId as String in your custom UserTest class, and accept that the userId in the user attribute will be wrong.

Another option would be to use the @Serialize annotation to store your User object in serialized mode. That way the long will remain untouched.

But more generally, you should not try to store classes that you do not control, because you will end up with issues like this. Here you're unable to convert the userId to a String , but you will also have issues if Google decides to updates its User class later.

Instead you should rather create your own MyUser class and manipulate it. Of course the downside is that you'll have to copy data from the original object to your custom one.

This looks like some sort of issue in GAE's User object. I would create an example that uses the low-level API and submit it to Google as a bug. It's interesting (and probably relevant) that the value is larger than an unsigned 64 bit integer, but since the value is a String, this is theoretically legal. What's going on under the covers is anyone's guess (outside of Google, that is).

Objectify is not involved; it just passes User objects as-is to the low level API.

If you look at the sources of User , you'll see that userId is not used in User object identity, ie equals() or hash() do not depend on it. The user identifier seems to be determined by auth domain and email.

So, do not worry about userId , use User.equals() to check for user identity.

I'm not sure how querying on field of type User is performed by GAE datastore, but I'd expect google to handle this properly (= the same as object identity). Anyhow you can test this easily with a quick query. If it does not perform as expected, then you can create your own user identity field in a similar way that .equals() does: contatenate auth domain and email together to create a user identity string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM