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

why Glassfish server throws NoSuchMethodError when creating an instance of java.time.LocalDate with ZoneId

我有创建 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.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.access0(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 method exists in Java 14, it does not in the LocalDate class 来自 Java 8。我希望您使用 JDK 14 进行编译,但 运行 它在Java.

的低版本

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

Since:

9

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

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

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

推荐:详情见JEP 247: Compile for Older Platform Versions


更新

的评论中提到使用 NetBeans 编译代码。我没有 NetBeans,但我相信它的功能与我使用的 Eclipse 非常相似,所以我将展示如何在 Eclipse 中修复此问题,并希望您可以自己将其应用于 NetBeans。

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

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

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

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

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

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

如果您不更改构建路径以匹配合规版本,请务必选中 Use '--release' option 复选框。

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

根据 Java8 和关于 LocalDateLocalDateTime 的进一步版本,GlassFish 使用的 (jre8) 和下一个版本有一些变化,从 Java9.

  • Java8
    ofInstantLocalDateTime

    上实施
  • Java9+

    ofInstantLocalDate.

    上实现

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

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

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

public LocalDate toLocalDate()

Gets the LocalDate part of this date-time. This returns a LocalDate with the same year, month and day as this date-time.