我试图将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)
基于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;
}
}
}
我最初的答案远远超出了你的实际问题,但直到后来我才意识到。这里有一个更简洁的版本,但我会把原文放在底部。
你遇到的问题是因为我建议的天真扩展有一个关键缺陷。
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来确定内部模型中属性的名称。现在发生的是:
详细信息对话框中添加了一个组件,其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: 如何找到这些日期之间的天数?