java - 在实例重新启动之前,从 GAE HRD 中的 Json 创建的 JDO 无法正确转换回 Json

标签 java google-app-engine gson

我正在开发一个 Android 应用程序,使用 Google App-Engine 来存储和管理应用程序的数据。不幸的是,我遇到了一个我似乎无法解决的问题。

当用户创建新帐户时,会为他们创建一个新的“项目”。该项目包含任务,这些任务存储在 Project 类中的 ArrayList 中。因此,在项目类的构造函数中,所有内容都被实例化,并且任务是使用 Gson2.2.2 从包含 Json 格式数据的文本文件创建的。
所有这些都工作正常,如果我在 Appengine 管理控制台中查看数据存储区查看器,一切看起来都很好。创建帐户后,用户立即登录,当用户登录时,需要将任务发送到 Android 客户端。这就是它变得奇怪的地方。将任务序列化回 Json 格式时,它们似乎未初始化。所有字符串字段都是空的,并且整数都设置为 0,但是正在序列化正确数量的任务,因此列表已填充。这个问题一直存在,直到我手动关闭 GAE 中的实例。当使用新请求重新启动时,数据将正确序列化为 Json 格式,一切正常。显然这不好,我不能让服务器在每次新用户创建帐户时关闭它的实例,只是为了能够为他们提供正确的数据。所以,请帮我解决这个问题。我已经为此苦苦挣扎了很长一段时间。下面是准确重现问题的代码。

public class CreateData extends HttpServlet{

    public void doGet(HttpServletRequest req, HttpServletResponse resp){
        if(req.getParameter("name").length() > 1){
            PersistenceManager pm = PMF.get().getPersistenceManager();
            User u = new User(req.getParameter("name"));
            pm.makePersistent(u);
            pm.close();
            try {
                resp.getWriter().print("User created with name "+req.getParameter("name"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else if(req.getParameter("name").length() <= 1){
            try {
                resp.getWriter().print("Please supply a name with at least 2 characters");
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            try {
                resp.sendError(400);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

用户类

    public class User {
    public @interface Skip {
        // Field tag only annotation
    }

    @PrimaryKey
    @Persistent
    private String name;

    @Persistent
    private ArrayList<DataType> data;
    public User(String name) {
        this.name = name;
        data = new ArrayList<DataType>();
        createDataFromJSON();
    }

    public String getDatasAsJSON(){
        Gson gson = new GsonBuilder().setExclusionStrategies(new MyExclusionStrategy(Key.class)).create();
        Type taskType = new TypeToken<List<DataType>>(){}.getType();
        String json = gson.toJson(this.data, taskType);
        return json;
    }


    public void createDataFromJSON() {
        FileReader fr = null;
        try {
            fr = new FileReader(new File("WEB-INF/defaults.json"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        if (fr != null) {
            Type taskType = new TypeToken<List<DataType>>(){}.getType();
            data = new Gson().fromJson(fr, taskType);
        }
    }

    public class MyExclusionStrategy implements ExclusionStrategy {
        private final Class<?> typeToSkip;

        private MyExclusionStrategy(Class<?> typeToSkip) {
            this.typeToSkip = typeToSkip;
        }

        public boolean shouldSkipClass(Class<?> clazz) {
            return (clazz == typeToSkip);
        }

        public boolean shouldSkipField(FieldAttributes f) {
            return f.getAnnotation(Skip.class) != null;
        }
    }
}

数据类型类

public class DataType {
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;

    @Persistent
    private String name;

    @Persistent
    private int points;

    @Persistent
    private int unique;

    public DataType() {
    }

    public DataType(String name, int points, int unique){
        this.name = name;
        this.points = points;
        this.unique = unique;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPoints() {
        return points;
    }

    public void setPoints(int points) {
        this.points = points;
    }

    public int getUnique() {
        return unique;
    }

    public void setUnique(int unique) {
        this.unique = unique;
    }

}

获取数据的Servlet

public class GetData extends HttpServlet{
    public void doGet(HttpServletRequest req, HttpServletResponse resp){
        String name = req.getParameter("name");
        PersistenceManager pm = PMF.get().getPersistenceManager();
        User u = null;
        try{
            u = pm.getObjectById(User.class, name);
        }catch(JDOObjectNotFoundException e){
            try {
                resp.sendError(404);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        if(u != null){
            String response = u.getDatasAsJSON();

            try {
                resp.getWriter().print(response);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

和 JSON 数据

[ 
    {
      "name": "Hug",
      "unique": 1,
      "points": 20
    },
    {
      "name": "Tug",
      "unique": 2,
      "points": 40
    },
    {
      "name": "Rug",
      "unique": 3,
      "points": 50
    },
    {
      "name": "Jug",
      "unique": 4,
      "points": 100
    },
    {
      "name": "Smug",
      "unique": 5,
      "points": 20
    }
]

因此,创建一个名为“Arne”的新用户工作正常,对象在 HDR 中创建。当 Json 产生此响应时,从数据存储中请求对象

[{"points":0,"unique":0},{"points":0,"unique":0},{"points":0,"unique":0},{"points":0,"unique":0},{"points":0,"unique":0}]

在重新启动服务器实例时,相同的请求会给出此响应

[{"name":"Hug","points":20,"unique":1},{"name":"Tug","points":40,"unique":2},{"name":"Rug","points":50,"unique":3},{"name":"Jug","points":100,"unique":4},{"name":"Smug","points":20,"unique":5}]

抱歉发了这么长的帖子,但希望有人能指出我做错了什么。提前谢谢了! 此致, 伊瓦尔

最佳答案

不幸的是,似乎没有人能够回答这个问题,尽管我已经找到了解决方法。我仍然认为这需要一个合适的解决方案,但至少我现在通过遍历所有对象并使用对象中某个字段的值分配一个临时变量来让它工作。这似乎迫使它们进行初始化,并且返回的 JSON 实际上填充了正确的字段。

public class GetData extends HttpServlet{
    public void doGet(HttpServletRequest req, HttpServletResponse resp){
        String name = req.getParameter("name");
        PersistenceManager pm = PMF.get().getPersistenceManager();
        User u = null;
        try{
            u = pm.getObjectById(User.class, name);
        }catch(JDOObjectNotFoundException e){
            try {
                resp.sendError(404);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        if(u != null){
            //By adding this seemingly pointless loop
            //the objects will actually return populated fields
            //when converted back to JSON
            for(DataType dt : u.getData()){
                String temp = dt.getName();
            }
            String response = u.getDatasAsJSON();

            try {
                resp.getWriter().print(response);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

关于java - 在实例重新启动之前,从 GAE HRD 中的 Json 创建的 JDO 无法正确转换回 Json,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15622211/

相关文章:

java - Spring 3.2 验证请求参数,ControllerAdvice 未格式化响应

java - 如何使用 GDB 从 native 调用调试到 java 函数?

java - 我可以让 Java 应用程序等待后台进程完成吗?

java - 使用 log4j 创建多个不同内容的日志文件

java - Google Gson - com.google.gson.JsonSyntaxException : java. lang.IllegalStateException:需要一个字符串,但实际上是 BEGIN_OBJECT

java - 如何禁用 gson 中的字符编码?

java - 在 GAE 中部署时包含 appengine-api-1.0-sdk.jar

python - 使用自定义验证器存储重复的 KeyProperty 时出现 BadValueError

google-app-engine - Google Cloud Endpoint - 生成 PDF

java - IllegalStateException - 使用 Gson 使用字符串数组序列化映射