为什么 Glassfish 服务器在使用 ZoneId 创建 java.time.LocalDate 实例时抛出 NoSuchMethodError

问题描述

我有这段代码可以创建 java.time.LocalDate 的一个实例。我用 JDK 14 编译它,它运行没有任何错误

public void foo(Date d){
  LocalDate d1 = LocalDate.ofInstant(d.toInstant(),ZoneId.systemDefault());
  System.out.println("Created LocalDate from Date: "+d1);
}

当我尝试在 Glassfish 服务器 5.1 上运行的 JSF 页面支持 bean 中执行相同的操作时,它会引发 NoSuchMethodError。

public void validateDateTimeLine(FacesContext fc,UIComponent ui,Object value) {
        Date then = (Date) value;
        try {
            LocalDate dthen = LocalDate.ofInstant(then.toInstant(),ZoneId.systemDefault());
            LocalDate Now = LocalDate.ofInstant(Instant.Now(),ZoneId.systemDefault());
            ....................................
        } catch (Exception | NoSuchMethodError e) {
            
        }
}

堆栈跟踪:

java.lang.NoSuchMethodError: java.time.LocalDate.ofInstant(Ljava/time/Instant;Ljava/time/ZoneId;)Ljava/time/LocalDate;
    at org.me.mavenlistservicedb.bean.LoginManagment.validateDateTimeLine(LoginManagment.java:176)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:181)
    at com.sun.el.parser.AstValue.invoke(AstValue.java:289)
    at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:304)
    at org.jboss.weld.module.web.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
    at org.jboss.weld.module.web.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
    at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:107)
    at javax.faces.validator.MethodExpressionValidator.validate(MethodExpressionValidator.java:109)
    at javax.faces.component.UIInput.validateValue(UIInput.java:1248)
    at javax.faces.component.UIInput.validate(UIInput.java:1037)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1334)
    at javax.faces.component.UIInput.processValidators(UIInput.java:757)
    at javax.faces.component.UIData.iterate(UIData.java:2150)
    at javax.faces.component.UIData.processValidators(UIData.java:1273)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1298)
    at javax.faces.component.UIForm.processValidators(UIForm.java:269)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1298)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1332)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:77)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:201)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:670)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1540)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:217)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:119)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:611)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:550)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:114)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:332)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:199)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:463)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:168)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:242)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadioStrategy.run0(WorkerThreadioStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadioStrategy.access$100(WorkerThreadioStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadioStrategy$WorkerThreadRunnable.run(WorkerThreadioStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
    at java.lang.Thread.run(Thread.java:748)

任何的想法?

谢谢

解决方法

虽然 LocalDate.ofInstant 方法存在于 Java 14 中,但它不在 Java 8 的 LocalDate 类中。我希望您使用 JDK 14 进行编译,但在较低版本上运行它

,

如果您阅读文档,即 LocalDate.ofInstant(Instant,ZoneId) 的 javadoc,您会发现:

因为:

9

代码是针对 Java 9+ 运行时库编译的,但使用 -target 1.8 编译,而您使用的是 Java 8。

不要这样做,即始终确保您编译的运行时库版本与生成的字节码版本相同。

解决方案:使用编译器选项 --release 8 而不是 -source 8 -target 8。该选项专门添加到 Java 9+ 编译器中,以便更轻松地针对旧版本的 Java 针对正确版本的运行时库进行编译。

推荐:请参阅JEP 247: Compile for Older Platform Versions了解更多详情。


更新

aran's answer 的注释中提到 NetBeans 用于编译代码。我没有 NetBeans,但我相信它的功能与我使用的 Eclipse 非常相似,因此我将展示如何在 Eclipse 中解决此问题,希望您可以将其应用到 NetBeans。

在 Eclipse 中,您需要在 2 个地方指定目标 Java 版本:

  • 类路径(或 Eclipse 中的构建路径):

    enter image description here

  • 编译器合规性级别(命令行上的 -source-target):

    enter image description here

在过去,这两个应该总是指同一个版本,例如如此处所示,其中构建路径是指安装 JDK 15 的位置,并且合规性级别设置为 15

从 Java 9 和新的 --release 编译器选项开始,您可以针对较旧版本的 Java,而无需安装此类较旧版本。

让构建路径指向 JDK 15,您可以将合规版本更改为例如8、如果您还选中 Use '--release' option 复选框(蓝色圆圈)。

如果您不更改构建路径以匹配合规版本,则选中 Use '--release' option 复选框非常重要。

这样做将确保编译器在调用 LocalDate.ofInstant() 时失败,因为该方法在 JDK 8 中不存在,即使构建路径上仍有 JDK 15。

,

根据关于 LocalDateLocalDateTime 的 Java8 和更高版本,GlassFish 使用的一个 (jre8) 和从 Java9 开始的下一个版本有一些变化。

  • Java8
    ofInstantLocalDateTime

    上实现
  • Java9+

    ofInstantLocalDate 上实现。

为了遵循您的逻辑,您可以这样做:

LocalDateTime dTime = LocalDateTime.ofInstant(then.toInstant(),ZoneId.systemDefault());
LocalDate dthen = dTime.toLocalDate();

LocalDateTimetoLocalDate() 将允许您获得适当的变量类型:LocalDate

public LocalDate toLocalDate()

获取其中的 LocalDate 部分 约会时间。这将返回具有相同年月日的 LocalDate 作为这个日期时间。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...