当前位置: 首页 > 知识库问答 >
问题:

JAVA时间LocalDate和Wicket 7 DateTextField

佘飞鸣
2023-03-14

我试图将Wicket组件DateTextField与类型为java.time.LocalDate的属性连接。

按照这个答案中的提示,我尝试实现一个自定义的CompoundPropertyModel,其中包含一个java。时间Localdate属性。我正在使用Wicket 7.6和JDK 8。

我不熟悉Wicket和Java泛型。

这是我的代码:

类LocaldateModel

import java.time.*;
import java.util.Date;
import org.apache.wicket.model.IModel;

public class LocalDateModel implements IModel<Date>
{
    private static final long serialVersionUID = 7262517323706786573L;
    private IModel<LocalDate> localDateModel;

    public LocalDateModel(IModel<LocalDate> localDateModel)
    {
        this.localDateModel = localDateModel;
    }

    @Override
    public Date getObject()
    {
        return Date.from(localDateModel.getObject().atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    @Override
    public void setObject(Date object)
    {
        localDateModel.setObject(
                Instant.ofEpochMilli(object.getTime()).atZone(ZoneId.systemDefault()).toLocalDate());
    }

    @Override
    public void detach()
    {
        localDateModel.detach();
    }
}

类LocalDateModelButAlsoWrapping

import java.time.Localdate;
import java.util.Date;

public class LocalDateModelButAlsoWrapping<T> extends LocalDateModel implements IWrapModel<Date>
{
    private static final long serialVersionUID = -8539316259078354206L;

    private IModel<Date> dateModel;

    public LocalDateModelButAlsoWrapping(IModel<LocalDate> localDateModel)
    {
        super(localDateModel);
        LocalDate localDate=localDateModel.getObject();
        dateModel.setObject(Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
    }

    @Override
    public IModel<Date> getWrappedModel()
    {
        return dateModel;
    }

    @Override
    public void setObject(Date object)
    {
       dateModel.setObject(object);
    }
}

类MyLocalDateCompound属性模型

import java.time.Localdate;
import org.apache.wicket.Component;
import org.apache.wicket.model.*;

public class MyLocalDateCompoundPropertyModel<T> extends CompoundPropertyModel<T>
{
    private static final long serialVersionUID = 7112056989820105247L;

    public MyLocalDateCompoundPropertyModel(IModel<T> model)
    {
        super(model);
    }

    public MyLocalDateCompoundPropertyModel(T object)
    {
        super(object);
    }

    @Override
    public <T> IWrapModel<T> wrapOnInheritance(Component component)
    {
        IWrapModel<T> actualModel;
        actualModel = super.wrapOnInheritance(component);

        if (actualModel.getObject() instanceof LocalDate)
        {
            return new LocalDateModelButAlsoWrapping(actualModel);
        }
        else
        {
            return actualModel;
        }
    }
}

使用LocalDate属性初始化

import java.time.Localdate;

public class CustomerUI implements Serializable
{
    private static final long serialVersionUID = -4071467669346190367L;

    private CustomerDTO customer;

    public LocalDate getActiveUntil()
    {
        return customer.getActiveUntil();
    }

    public void setActiveUntil(LocalDate activeUntil)
    {
        customer.setActiveUntil(activeUntil);
    }

    // more delegating getters and setters
}    

创建组件

    detailsDialog = new MyCustomerDetailsDialog("createDialog",
            new MyLocalDateCompoundPropertyModel<CustomerUI>(Model.of(new CustomerUI())))

以下是错误消息:

最后一个原因:无法为class:class-example解析属性。用户界面。顾客CustomerUI表达式:dialog WicketMessage:无法使用构造函数的公共示例实例化页面。用户界面。顾客MyCustomerOverviewPage()。在构造期间引发了异常!

Stacktrace:

org.apache.wicket.WicketRuntimeException: Property could not be resolved for class: class example.ui.customer.CustomerUI expression: dialog
     at org.apache.wicket.core.util.lang.PropertyResolver.getGetAndSet(PropertyResolver.java:393)
     at org.apache.wicket.core.util.lang.PropertyResolver.getObjectWithGetAndSet(PropertyResolver.java:355)
     at org.apache.wicket.core.util.lang.PropertyResolver.getObjectWithGetAndSet(PropertyResolver.java:261)
     at org.apache.wicket.core.util.lang.PropertyResolver.getValue(PropertyResolver.java:111)
     at org.apache.wicket.model.AbstractPropertyModel.getObject(AbstractPropertyModel.java:86)
     at example.ui.models.MyLocalDateCompoundPropertyModel.wrapOnInheritance(MyLocalDateCompoundPropertyModel.java:35)
     at org.apache.wicket.Component.initModel(Component.java:3841)
     at org.apache.wicket.Component.getDefaultModel(Component.java:1625)
     at org.apache.wicket.MarkupContainer$2.component(MarkupContainer.java:876)
     at org.apache.wicket.MarkupContainer$2.component(MarkupContainer.java:872)
     at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:144)
     at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:123)
     at org.apache.wicket.util.visit.Visits.visitChildren(Visits.java:192)
     at org.apache.wicket.MarkupContainer.visitChildren(MarkupContainer.java:983)
     at org.apache.wicket.MarkupContainer.setDefaultModel(MarkupContainer.java:871)
     at example.ui.customer.MyCustomerDetailsDialog.<init>(MyCustomerDetailsDialog.java:44)
     at example.ui.customer.MyCustomerOverviewPage$2.<init>(MyCustomerOverviewPage.java:95)

第35行是:

 if (actualModel.getObject() instanceof LocalDate)

共有2个答案

戚翰飞
2023-03-14

基于WiseTrees的回答,我修改了我的类。这个解决方案是有效的,尽管在类MyLocalDateCompoundProperty tyModel中有与类型转换相关的警告。

类MyLocalDateModel

package example.ui.models;

import java.time.*;
import java.util.Date;
import org.apache.wicket.model.IModel;
import example.misc.MyDateTimeUtil;

public class MyLocalDateModel implements IModel<Date>
{
    private static final long serialVersionUID = 7262517323706786573L;
    private IModel<LocalDate> localDateModel;

    public MyLocalDateModel(IModel<LocalDate> localDateModel)
    {
        this.localDateModel = localDateModel;
    }

    @Override
    public Date getObject()
    {
        return MyDateTimeUtil.createDateFromLocalDate(localDateModel.getObject());
    }

    @Override
    public void setObject(Date object)
    {
        localDateModel.setObject(MyDateTimeUtil.createLocalDateFromDate(object));
    }

    @Override
    public void detach()
    {
        localDateModel.detach();
    }
}

类MyWrappingLocalDateModel

package example.ui.models;

import java.time.LocalDate;
import java.util.Date;
import org.apache.wicket.model.*;

public class MyWrappingLocalDateModel extends MyLocalDateModel implements IWrapModel<Date>
{
    private static final long serialVersionUID = -8539316259078354206L;

    public MyWrappingLocalDateModel(IModel<LocalDate> localDateModel)
    {
        super(localDateModel);
    }

    @Override
    public IModel<Date> getWrappedModel()
    {
        return Model.of(super.getObject());
    }

    @Override
    public void setObject(Date object)
    {
       super.setObject(object);
    }
}

类MyLocalDateCompoundPropertyModel

package example.ui.models;

import java.time.LocalDate;
import org.apache.wicket.Component;
import org.apache.wicket.extensions.markup.html.form.DateTextField;
import org.apache.wicket.model.*;

public class MyLocalDateCompoundPropertyModel<T> extends CompoundPropertyModel<T>
{
    private static final long serialVersionUID = 7112056989820105247L;

    public MyLocalDateCompoundPropertyModel(IModel<T> model)
    {
        super(model);
    }

    public MyLocalDateCompoundPropertyModel(T object)
    {
        super(object);
    }

    @Override
    public <T> IWrapModel<T> wrapOnInheritance(Component component)
    // warning: type Parameter 'T' hides type parameter 'T'
    {
        IWrapModel<T> actualModel;
        actualModel = super.wrapOnInheritance(component);

        if ((component instanceof DateTextField) && (actualModel.getObject() instanceof LocalDate))
        {
            return (IWrapModel<T>) new MyWrappingLocalDateModel((IModel<LocalDate>) actualModel);
            // warning: unchecked cast
        }
        else
        {
            return actualModel;
        }

    }
}
计承德
2023-03-14

我最初的答案远远超出了你的实际问题,但直到后来我才意识到。这里有一个更简洁的版本,但我会把原文放在底部。

你遇到的问题是因为我建议的天真扩展有一个关键缺陷。

CompoundProperty tyModel将尝试为任何没有模型的子组件实例化模型。当您使用常规CompoundProperty tyModel时,这不是问题;当模型不相关时,永远不会尝试获取其对象。

这里发生的事情是,模型的这个扩展不仅会为任何无模型的子级创建一个模型,而且还会为了检查属性的类型而尝试对其进行评估。

问题是,您可能有子组件(例如链接),其中模型不一定会被解析为任何内容。在这个特定的实例中,您似乎添加了一个ID为“dialog”的组件;即使它可能不一定需要模型,CompoundPropertyModel仍将为其调用,并且它将尝试从底层的CustomerUI对象中获取名为“dialog”的属性。

因此,为了不遇到这个问题,您需要防止扩展每次都评估模型

@Override
public <T> IWrapModel<T> wrapOnInheritance(Component component)
{
    IWrapModel<T> actualModel;
    actualModel = super.wrapOnInheritance(component);

    if (component instanceof DateTextField && actualModel.getObject() instanceof LocalDate)
    {
        return new LocalDateModelButAlsoWrapping(actualModel);
    }
    else
    {
        return actualModel;
    }
}

希望有帮助。

要理解代码不起作用的原因,需要了解CompoundPropertyModel的工作原理。

我将用你的一段稍加修改的代码片段来说明这一点

IModel<CustomerUI> customerUIModel = Model.of(new CustomerUI());
detailsDialog = new MyCustomerDetailsDialog("createDialog", new CompoundPropertyModel<CustomerUI>(customerUIModel));

假设我们想在detailsDialog中添加一个标签,显示CustomerUI的“activeDate”属性。如果我们没有使用CompoundPropertyModel,那么为了实现这一点,我们必须执行以下操作:

IModel<LocalDate> activeDateModel = PropertyModel(customerUIModel, "activeUntil");
detailsDialog.add(new Label("dialog", activeDateModel));

CompoundPropertyModel所做的是让我们绕过为组件提供模型,只需简单地

detailsDialog.add(new Label("activeDate"))

然后当页面被渲染时,一个组件将检测到它没有模型,因此它给了父模型一个向它提供模型的机会。

这就是CompoundPropertyModel的作用。它查看哪个组件请求提供模型,并准确地执行该操作。然而,它是如何做到这一点的?其实很简单

return new PropertyModel(innerModel, component.getId())

因此,由于这个简单的逻辑,您可以绕过在子组件上实例化您自己的模型,并将父组件的CompoundProperty tyModel提供给它们的模型提供给它们。然而,子组件的ID必须引用存储在复合属性模型中的模型对象的某些属性。否则,您将得到确切的错误:

Property could not be resolved for class: class example.ui.customer.CustomerUI expression: dialog

现在,让我们看看CompoundPropertyModel的扩展。当组件请求为自己获取模型时,您的扩展将执行以下操作:

@Override
public <T> IWrapModel<T> wrapOnInheritance(Component component)
{
    IWrapModel<T> actualModel;
    actualModel = super.wrapOnInheritance(component);

    if (actualModel.getObject() instanceof LocalDate)
    {
        return new LocalDateModelButAlsoWrapping(actualModel);
    }
    else
    {
        return actualModel;
    }
}

它的作用是调用CompoundProperty tyModel的默认行为来实例化组件的模型,然后检测该模型是否返回LocalDate的实例,并包装该模型,以便有一个返回Date的模型。

由于扩展仍然依赖于CompoundPropertyModel的默认行为,因此它仍将使用组件的wicket ID来确定内部模型中属性的名称。现在发生的是:

  1. 您在详细信息对话框中添加了一个组件,其wicket ID为“dialog”

所以最后你做的一切都是对的。唯一的问题是你添加了一个子组件,它的wicket ID没有引用一个有效的属性。

这也展示了一个问题。我提供的实现是幼稚的。每当添加一个没有模型的组件时,这个扩展模型会为它创建一个模型,但它也总是试图获得它的值。所以如果你添加一个甚至不应该有模型的子组件,复合属性模型甚至会对这些组件起作用。

因此,更持久的解决方案将是不涉及试图获得模型价值的东西。例如,您可以检查组件是否为DateTextField

@Override
public <T> IWrapModel<T> wrapOnInheritance(Component component)
{
    IWrapModel<T> actualModel;
    actualModel = super.wrapOnInheritance(component);

    if (component instanceof DateTextField && actualModel.getObject() instanceof LocalDate)
    {
        return new LocalDateModelButAlsoWrapping(actualModel);
    }
    else
    {
        return actualModel;
    }
}

这将推迟查看模型,直到您确定您试图实例化其模型的组件确实需要LocalDate模型。

 类似资料:
  • 我正在尝试转换java。util。日期至java。时间本地日期: 但是,当有例如22:25的一天时间时,我选择ZoneId,例如:。 即将推出的本地日期将有不同的日期(因为该区域增加了6小时),例如欧洲/明斯克: 我想在结果的LocalDate中保留与该实例相同的日期。一些方法如何解决这个问题?我想可能有几种方法。

  • 我试图理解Java8中引入的新日期和时间API。 我在日志文件中有一个unix时间戳,我需要对它进行处理,以确定它属于今天或昨天的哪个小时。 我在Android Studio中遇到了一个不寻常的错误,我想更好地理解它。

  • 问题内容: Joda-time具有一个Interval类,该类介于DateTime之间。什么可以用于一系列LocalDate? 我想要一个表示例如“从2011年1月1日到2011年10月1日”的对象,而没有时间(或时区)进入画面。 据我所知,joda-time没有内置任何功能。如果不存在任何东西,而我们会创建它,它应该是什么样?最重要的是,它可以实现joda- time的哪些接口以最好地集成到其他

  • 问题内容: 在Java 8和Java 8 之间进行转换的最佳方法是什么? 问题答案: 从转换为: 转换回来比较简单:

  • 问题内容: 这个问题已经在这里有了答案 : 如何将LocalDate转换为SQL Date Java? (3个答案) 5年前关闭。 在和(Java8)之间进行转换的正确方法是什么? 问题答案: 的Java 8版本(及更高版本)已内置对的支持,包括和。 转换为可以使用 并转换为: 时区: 该类型不存储时区信息,而存储。因此,使用上述转换时,结果取决于系统的默认时区(如注释中所指出)。 如果您不想依赖

  • 我有两个s: 如何找到这些日期之间的天数?