为啥在托管模式下运行 GWT App Engine 应用程序时会出现 ClassNotPersistableException?

Posted

技术标签:

【中文标题】为啥在托管模式下运行 GWT App Engine 应用程序时会出现 ClassNotPersistableException?【英文标题】:Why do I get ClassNotPersistableException while running GWT App Engine application in hosted mode?为什么在托管模式下运行 GWT App Engine 应用程序时会出现 ClassNotPersistableException? 【发布时间】:2010-11-03 13:09:05 【问题描述】:

当我尝试对我的 GWT/App Engine 应用程序的本地 JDO 数据存储执行查询时,我随机收到 org.datanucleus.exceptions.ClassNotPersistableException。这只发生在我在托管模式下运行应用程序时。当我将它部署到 Google App Engine 时,一切正常。

堆栈跟踪:

org.datanucleus.exceptions.ClassNotPersistableException: The class "com.wayd.server.beans.WinePost" is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.
    at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:305)
    at org.datanucleus.ObjectManagerImpl.getExtent(ObjectManagerImpl.java:3700)
    at org.datanucleus.jdo.JDOPersistenceManager.getExtent(JDOPersistenceManager.java:1515)
    at com.wayd.server.WinePostServiceImpl.getPosts(WinePostServiceImpl.java:212)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:527)
    ... 25 more
Caused by: org.datanucleus.exceptions.ClassNotPersistableException: The class "com.wayd.server.beans.WinePost" is not persistable. This means that it either hasnt been enhanced, or that the enhanced version of the file is not in the CLASSPATH (or is hidden by an unenhanced version), or the Meta-Data/annotations for the class are not found.
    at org.datanucleus.ObjectManagerImpl.assertClassPersistable(ObjectManagerImpl.java:3830)
    at org.datanucleus.ObjectManagerImpl.getExtent(ObjectManagerImpl.java:3693)
    ... 32 more)

WinePost 类是一个非常简单的 JDO 持久化类:

@PersistenceCapable(identityType = IdentityType.APPLICATION) 公共类 WinePost

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;

@Persistent
private User author;

@Persistent
private String grape;

@Persistent
private String comment;

public WinePost(final User author, final String grape,
        final String comment) 
    super();
    this.grape = grape;
    this.comment = comment;


public User getAuthor() 
    return author;


public void setAuthor(final User author) 
    this.author = author;


public Long getId() 
    return id;


public void setId(final Long id) 
    this.id = id;


public String getGrape() 
    return grape;


public void setGrape(final String grape) 
    this.grape = grape;


public String getComment() 
    return comment;


public void setComment(final String comment) 
    this.comment = comment;


public String getUserNickname() 
    String retVal = null;
    if (author != null) 
        retVal = author.getNickname();
    
    return retVal;


public WinePostModel getWinePostModel() 
    final WinePostModel winePostModel = new WinePostModel(grape, vintage, getUserNickName());
    return winePostModel;

数据存储区查询通过以下方法进行:

public ArrayList<WinePostModel> getPosts() 
        final ArrayList<WinePostModel> posts = new ArrayList<WinePostModel>();
        final PersistenceManager persistenceManager = PMF.get()
        .getPersistenceManager();

        final Extent<WinePost> winePostExtent = persistenceManager.getExtent(
                WinePost.class, false);
        for (final WinePost winePost : winePostExtent) 
            posts.add(winePost.getWinePostModel());
        
        winePostExtent.closeAll();

        return posts;
    

【问题讨论】:

【参考方案1】:

我很确定您的代码没有任何问题。您收到此错误的原因是 Datanucleus 增强器存在问题。

如果您看到此错误,请退出 Jetty 并检查 Eclipse 中的控制台(您需要在控制台窗口上方的小工具栏中选择正确的控制台)。它应该是这样的:

DataNucleus Enhancer(1.1.4 版):类的增强 DataNucleus Enhancer 成功完成 X 类。计时:输入=547 毫秒,增强=76 毫秒,总计=623 毫秒。详情请查阅日志

... 其中 X 是它已处理的类数。该数字应等于您定义的“实体”分类的数量。

但有时,由于某种原因,它会显示 0,这就是您收到 ClassNotPersistableException 错误的原因。

要修复,打开一个实体类并更改某些内容(添加空格或其他内容)并保存。检查控制台,直到它说它已经增强了您的所有实体类。然后重启调试器再试一次。

【讨论】:

我遇到了同样的问题,你是对的,eclipse 中的增强器没有运行,当我重新启动时它就像魅力一样工作【参考方案2】:

发布以供遇到相同问题的任何人将来参考,尽管这是一个旧线程。

我遇到了“相同”的问题,发现我的类路径有多个 datanucleus-appengine-1.0.7.final.jar 实例。我从尝试构建工作区时提示的日志中了解到这一点。这是日志内容。

java.lang.RuntimeException: 意外异常 在 com.google.appengine.tools.enhancer.Enhancer.execute(Enhancer.java:59) 在 com.google.appengine.tools.enhancer.Enhance.(Enhance.java:60) 在 com.google.appengine.tools.enhancer.Enhance.main(Enhance.java:41) 引起:java.lang.reflect.InvocationTargetException 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 com.google.appengine.tools.enhancer.Enhancer.execute(Enhancer.java:57) ... 2 更多 原因:org.datanucleus.exceptions.NucleusException:插件(Bundle)“org.datanucleus.store.appengine”已注册。确保类路径中没有同一个插件的多个 JAR 版本。网址“file:/G:/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.4_1.3.4.v201005212032/appengine-java-sdk-1.3.4/lib/user/orm/datanucleus-appengine -1.0.7.final.jar" 已经注册,并且您正在尝试注册位于 URL "file:/G:/WS_Quotemandu/quotemandu/war/WEB-INF/lib/datanucleus-appengine-1.0. 7.final.jar。” 在 org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:434) 在 org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:340) 在 org.datanucleus.plugin.NonManagedPluginRegistry.registerExtensions(NonManagedPluginRegistry.java:222) 在 org.datanucleus.plugin.NonManagedPluginRegistry.registerExtensionPoints(NonManagedPluginRegistry.java:153) 在 org.datanucleus.plugin.PluginManager.registerExtensionPoints(PluginManager.java:82) 在 org.datanucleus.OMFContext.(OMFContext.java:160) 在 org.datanucleus.enhancer.DataNucleusEnhancer.(DataNucleusEnhancer.java:172) 在 org.datanucleus.enhancer.DataNucleusEnhancer.(DataNucleusEnhancer.java:150) 在 org.datanucleus.enhancer.DataNucleusEnhancer.main(DataNucleusEnhancer.java:1157) ... 7 更多

G:/eclipse/plugins/com.google.appengine.eclipse.sdkbundle.1.3.4_1.3.4.v201005212032/appengine-java-sdk-1.3.4/lib/user/orm/datanucleus-appengine-1.0。 7.final.jar

文件:/G:/WS_Quotemandu/quotemandu/war/WEB-INF/lib/datanucleus-appengine-1.0.7.final.jar

希望这会有所帮助!

【讨论】:

我遇到了同样的问题,当我从我的类路径中删除重复的 JDO jar 时,它得到了解决。谢谢。【参考方案3】:

我以前见过非常相似的东西,它与同时被不同方法调用的persistantManager 有关。发生这种情况是因为 pm 应该是一个 single instance (它不是 singleton 所以你必须自己管理它)。

一旦部署,条件可能会在开发环境和生产环境之间发生变化,因此这也可以解释您所看到的情况。

通过在使用 pm 的方法声明中使用 synchronized 解决了问题。

也许这不是你的情况,但你可能想试一试。

【讨论】:

+1 我不确定我是否遵循您在单例和单实例之间的区别。但是没有两个开放的 PersistenceManager 是一个很好的问题,这似乎是我自己困难的根源。 这确实是一个常见问题 - 单例有一个私有构造函数和一个 getInstance 方法,该方法检查是否已经存在实例,如果存在则返回,否则创建一个新实例。单个实例是一个普通类,在整个应用程序中只能实例化一次,这意味着需要某种包装器来确保您始终使用相同的。或者你在使用给定类的方法中使用同步。【参考方案4】:

我有同样的问题,由于安装了 2 个版本。

首先我安装了 Google App Engine Sdk 1.8.8,然后更新并 eclipse 下载了 Google App Engine Sdk 1.8.9

拥有 2 个版本会导致引发此错误。尽管一切都编译得很好,但我没有意识到 datanucleus 增强器控制台日志在编译时警告我这个错误,只是发现控制台存在 ;-)

就我而言,解决方案是只保留较新版本的旧版本:

右键单击项目 -> 属性 深入了解 Google/App Engine 在右侧,您将看到一个名为 Configure SDKs 的按钮链接 将打开一个新窗口,显示已安装的所有 SDK 版本 选择不需要的版本并点击删除按钮

为确保旧版本(1.8.8)被完全删除:

打开文件资源管理器C:\Users\XXX\.eclipse\org.eclipse.platform_4.3.0_1709980481_win32_win32_x86_64\plugins,其中 XXX 是您的 Windows 用户。 如果文件夹com.google.appengine.eclipse.sdkbundle_1.8.8存在,删除它!

现在,如果您打开 datanucleus 增强器控制台,该类将显示成功增强。

【讨论】:

【参考方案5】:

检查您的编译器版本。它应该是 1.7 或更低。它不应该是 1.8。我也得到了同样的东西,我改变了编译器,然后它对我有用。

【讨论】:

【参考方案6】:

我遇到了同样的问题。 在我的情况下,代码在构建过程中通过 maven clean + install 正确处理,请参见下面的日志摘录:

增强(持久):nl.jdoexample.model.Product 增强(持久):nl.jdoexample.model.Book

问题是在执行之前(在 Intellij 中)执行时(请参阅此运行/调试配置)命令“make”被执行,从而删除了增强的 java 文件。这导致错误弹出。

在 Intellij 中问题的修复(但也可以在 Eclipse 或 Netbeans 中完成): - jdo示例 - 生命周期: - 编辑配置(运行/调试配置): - jdo-example [安装] 命令行:全新安装

运行/调试配置: -应用: - 删除“制作” - 新的执行定义: - 名称:执行 main jdoExample - 配置: - 主类:nl.jdoexample.main

这样应用程序在执行前不会再次编译,从而删除增强的java文件。 这在我的情况下是成功的。希望这会有所帮助。

【讨论】:

【参考方案7】:

“类“com.wayd.server.beans.WinePost”是不可持久的。这意味着它没有被增强,或者文件的增强版本不在 CLASSPATH 中(或者被未增强的隐藏版本),或者找不到该类的元数据/注释。”

那么为什么不检查这三个条件中的每一个呢?其中之一是正确的。

【讨论】:

我检查了它们,一切似乎都很好。当我在 App Engine 上部署该应用程序时,它运行良好,但我随机收到此异常。 可能报告错误? Java 支持仍处于“测试阶段” 如果出现该消息,那么这三件事中的一件是真实的。没有别的了。有字节码反编译器可用于检查增强。可以很容易地打印出关于元数据/注释是否存在的 CLASSPATH。可以轻松检查日志(在 DEBUG 级别)并提供大量信息,说明找到了哪些元数据。 -1 这个问题是真诚地提出的。你基本上告诉他阅读手册。 手册不正确?请提供你不是的证据,我很乐意更新它。正如另一个答复所说,更改一个班级并重新增强......所以班级没有得到增强。然后你回溯,发现 Eclipse 的 GAE/J 插件在检测类何时更改时不可靠。

以上是关于为啥在托管模式下运行 GWT App Engine 应用程序时会出现 ClassNotPersistableException?的主要内容,如果未能解决你的问题,请参考以下文章

gwt- 如何读取文本文件(Google App Engine servlet)?

我的 Java App Engine GWT 应用程序的 Web 服务 API

为啥在调试模式下启动 GWT 时,我的断点不会中断

如何将 maven 托管依赖项复制到 war\web-inf\lib 中,以便我可以在 Eclipse 中以调试模式运行我的 GWT 2.0 应用程序?

Google Web Toolkit (GWT) rpc 到 Google App Engine (GAE) 上的 Python 服务器

无法通过 unix 套接字从托管在不同 GCP 项目中的 App Engine 柔性环境连接到 Cloud SQL