为 Play 构建 WAR 时 .class 位置出错!框架应用

发布于 2024-12-09 22:11:57 字数 2377 浏览 0 评论 0原文

我正在开发 1.2 Play!框架应用程序,在 Tomcat 6 上将其部署为 WAR 时遇到问题。

我的应用程序的一页显示信息列表。 这些信息是从 .yml 文件中检索的。 因此,我有一个控制器,可以从 .yml 文件生成 Iterable,如下所示:

public static void myFunction() {
    Constructor constructor = new Constructor(MyClass.class); // org.yaml.snakeyaml.constructor.Constructor
    constructor.addTypeDescription(new TypeDescription(MyClass.class));
    Yaml yaml = new Yaml(constructor);
    Iterable<Object> listOfInfo = yaml.loadAll(Application.class.getResourceAsStream("/my-file.yml"));
    render("Application/my-page.html", listOfInfo);
}

重要的一点是 MyClass 位于在 app/my/company/my-app/ 包 (my.company.my-app.MyClass) 中。

当我使用 play run 运行我的应用程序时,没有问题。

现在,我构建 WAR 包(使用 play war -o some/dir --zip),并将生成的 WAR 安装在 Tomcat (6.0) 上。 服务器启动后,尝试访问相应的页面,我收到以下错误:

@683lh76fn
Internal Server Error (500)

Template execution error (In /app/views/Application/my-page.html around line 9)
Execution error occured in template /app/views/Application/my-page.html. Exception raised was ConstructorException : null; Can't construct a java object f
or tag:yaml.org,2002:my.company.my-app.MyClass; exception=Class not found: my.company.my-app.MyClass.

play.exceptions.TemplateExecutionException: null; Can't construct a java object for tag:yaml.org,2002:my.company.my-app.MyClass; exception
=Class not found: my.company.my-app.MyClass
        at play.templates.BaseTemplate.throwException(BaseTemplate.java:84)
        at play.templates.GroovyTemplate.internalRender(GroovyTemplate.java:252)
        at play.templates.Template.render(Template.java:26)
        at play.templates.GroovyTemplate.render(GroovyTemplate.java:184)
        at play.mvc.results.RenderTemplate.<init>(RenderTemplate.java:24)
        at play.mvc.Controller.renderTemplate(Controller.java:659)
        at play.mvc.Controller.renderTemplate(Controller.java:639)
        at play.mvc.Controller.render(Controller.java:694)
        at controllers.Application.myFunction(Application.java:311)

如果我查看爆炸战争,我会看到 my.company.my-app.MyClass 是位于目录WEB-INF/application/precompiled/java/my/company/my-app/目录中。

如果我将此目录移动到 WEB-INF/classes 中,那么我就不会再收到此错误。

为什么会出现这个错误?我可以选择哪些选项来使其工作(无需手动修改 WAR)?

I'm working on a 1.2 Play! framework application, and I have a problem when deploying it as a WAR on a Tomcat 6.

One page of my application displays a list of information.
These information are retrieved from a .yml file.
So I have a controller that generate a Iterable<Object> from this .yml file, like that:

public static void myFunction() {
    Constructor constructor = new Constructor(MyClass.class); // org.yaml.snakeyaml.constructor.Constructor
    constructor.addTypeDescription(new TypeDescription(MyClass.class));
    Yaml yaml = new Yaml(constructor);
    Iterable<Object> listOfInfo = yaml.loadAll(Application.class.getResourceAsStream("/my-file.yml"));
    render("Application/my-page.html", listOfInfo);
}

The important point is that MyClass is located in the app/my/company/my-app/ package (my.company.my-app.MyClass).

When I run my application using play run, there is no problem.

Now, I build the WAR package (using play war -o some/dir --zip), and I install this generated WAR on a Tomcat (6.0).
Once the server is started, and try to access the corresponding page, I get the following error:

@683lh76fn
Internal Server Error (500)

Template execution error (In /app/views/Application/my-page.html around line 9)
Execution error occured in template /app/views/Application/my-page.html. Exception raised was ConstructorException : null; Can't construct a java object f
or tag:yaml.org,2002:my.company.my-app.MyClass; exception=Class not found: my.company.my-app.MyClass.

play.exceptions.TemplateExecutionException: null; Can't construct a java object for tag:yaml.org,2002:my.company.my-app.MyClass; exception
=Class not found: my.company.my-app.MyClass
        at play.templates.BaseTemplate.throwException(BaseTemplate.java:84)
        at play.templates.GroovyTemplate.internalRender(GroovyTemplate.java:252)
        at play.templates.Template.render(Template.java:26)
        at play.templates.GroovyTemplate.render(GroovyTemplate.java:184)
        at play.mvc.results.RenderTemplate.<init>(RenderTemplate.java:24)
        at play.mvc.Controller.renderTemplate(Controller.java:659)
        at play.mvc.Controller.renderTemplate(Controller.java:639)
        at play.mvc.Controller.render(Controller.java:694)
        at controllers.Application.myFunction(Application.java:311)

If I have a look in the exploded war, I see that my.company.my-app.MyClass is located in the directory WEB-INF/application/precompiled/java/my/company/my-app/ directory.

If I move this directory into WEB-INF/classes, then I don't get this error anymore.

Why does this error occurs? What are my options to make it work (without modifying manually the WAR)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

知你几分 2024-12-16 22:11:57

默认情况下,Tomcat 仅查看 /WEB-INF/classes 和 /WEB-INF/lib(对于每个 war 文件)中的文件,因为它们包含在类路径中。您可以做很多事情。

  • 将您的类放入 Tomcat lib 文件夹中,它们将由通用加载器而不是 web 应用程序加载器处理。 (不推荐,因为它们可用于其他应用程序)
  • 您可以在conf/catalina.properties中启用共享加载器并使用您想要的任何目录。
  • 在“/bin/setclasspath.sh”脚本中添加 CLASSPATH 变量的路径(或 setclasspath.bat
    视窗)。

就我个人而言,我会修复/修改构建 war 文件的方式,并确保将类复制到 WEB-INF/classes 而不是 WEB-INF/application 文件夹。

By the default, Tomcat only looks at files in /WEB-INF/classes and /WEB-INF/lib (for each war file) as they are included in the classpath. There are a number of things you could do..

  • Put your classes in the Tomcat lib folder and they'll be handled by the common loader rather than the webapp loader. (not recommended as they will be available to other apps)
  • You can enable the shared loader in conf/catalina.properties and use whatever directory you want.
  • add the path to the CLASSPATH variable in the '/bin/setclasspath.sh' script (or setclasspath.bat for
    Windows).

Personally i would fix/modify how i build the war file and make sure that the classes are copied to WEB-INF/classes instead of WEB-INF/application folder.

这个俗人 2024-12-16 22:11:57

我终于找到了这个问题的答案!

Yaml 解析器 (snakeyaml) 创建自己的类加载器以解析 .yml 文件。游戏的结构! Framework使用自己的ClassLoader,编译后的类位于WEB-INF/application/precompiled/java目录下,这不是WAR标准。
因此,Yaml 无法检索类,特别是 MyClass.class

解决此问题的解决方案(除了使用 Ant 修改 WAR 之外)是 发挥吧! Yaml 解析器的类加载器。我不写:

Constructor constructor = new Constructor(MyClass.class);
constructor.addTypeDescription(new TypeDescription(MyClass.class));

我写:

CustomClassLoaderConstructor constructor = new CustomClassLoaderConstructor(MyClass.class, MyController.class.getClassLoader());
constructor.addTypeDescription(new TypeDescription(MyClass.class));

使用这个,我可以使用 Play 创建的 WAR!直接不再出现 Yaml 错误!

I finally found the answer of this problem!

The Yaml parser (snakeyaml) creates its own ClassLoader in order to parse a .yml file. The structure of the Play! framework uses its own ClassLoader, and the compiled classes are located in the WEB-INF/application/precompiled/java directory, which is not the WAR standard.
Due to that, Yaml was not able to retrieve the classes, in particular MyClass.class.

The solution to solve this issue (except by modifying the WAR using Ant for example), is to give the Play! ClassLoader to the Yaml parser. Instead of writing that:

Constructor constructor = new Constructor(MyClass.class);
constructor.addTypeDescription(new TypeDescription(MyClass.class));

I write:

CustomClassLoaderConstructor constructor = new CustomClassLoaderConstructor(MyClass.class, MyController.class.getClassLoader());
constructor.addTypeDescription(new TypeDescription(MyClass.class));

using this, I can use the WAR created by Play! directly without getting the Yaml error anymore!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文