GAE+Objectify - Parameterized type com.googlecode.objectify.Ref not supported

霸气de小男生 提交于 2019-11-29 12:03:40

Google Cloud Endpoints is unable to serialise the Ref object because it is an arbitrary object defined by objectify, therefore not supported as the error indicates.

This is known limitation with Cloud Endpoints in that it does not allow custom objects to be used. There is a whole discussion thread on this point in particular if you're interested: Cloud endpoints .api generation exception when using objectify (4.0b1) parameterized key

You will have to annotate your methods with @ApiResourceProperty and set its ignored attribute to true as illustrated in the code below:

import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Load;
import com.google.api.server.spi.config.AnnotationBoolean;
import com.google.api.server.spi.config.ApiResourceProperty;

@Entity
public class User 
{
    @Id private Long userId;
    private String userName;
    @Load private Ref<UserDetails> userDetails;
    @Load private Ref<UserPassword> userPassword;

    //getters & setters
    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
    public UserDetail getUserDetails(){
    }

    @ApiResourceProperty(ignored = AnnotationBoolean.TRUE) 
    public UserPassword getUserPassword(){
    }
}

If you still want to use the data held in those objects then consider adding some fields to your class to hold the data and initialise them after your User class has finished loading like so:

@Ignore String firstName;
@OnLoad
void trackUserDetails() 
{ 
    this.firstName = getUserDetails().getFirstName(); 
    // add more code here to set other fields, you get the gist
}

But in my opinion a better approach would be to reconsider the design of your class, or rather rethink what you're trying to do.

ApiResourceProperty annotation does not work for Google Emdpoints+Objectify combinations as Ref or Key is Objectify specific class and Google Endpoints does not recognize them and will give a error when you try to generate the Client Libraries. I changed the User class as below.

 @Id private Long userId;
 @Index private String userName;
 @Load private UserDetails userDetails;
 @Load private UserPassword userPassword;
 @Load private ArrayList<Account> userAccounts;

 //getters and setters

When I retrieve the user by user name as below, I get the User, UserDetails, UserPassword and also the list of User accounts thru the getters (in one shot)

@ApiMethod(name = "getUserByName", path = "get_user_by_name")
public User getUserByName(@Named("userName") String userName) {

    User user = null;
    try {
         user = ofy().load().type(User.class).filter("userName", userName).first().now();
         if(user != null)
             log.info("UserEndpoint.getUserByName...user retrieved="+user.getUserId());
         else
             log.info("UserEndpoint.getUserByName...user is null");
    } catch(Exception e) {
        log.info("UserEndpoint.getUserByName...exception="+e.getMessage());
    }
    return user;
}

When I use the Datastore Viewer on Google Console to view the data, I see some entries in the userDetails, userPassword and Accounts columns in the User table. I assume that these are references to the actual data in their respective tables and not a copy of the data itself. Hope this helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!