Validation 在搜索GWT验证示例时。。。你在哪里?
作为后续行动 我正在尝试添加JSR-303验证支持。我在这里遵循了Koma的配置建议:(注意:我使用的是GWT2.4的内置验证,而不是GWT验证) 同样,为了得到一些重用,我制作了一对类,ValidatableInputCell和AbstractValidatableColumn。我从以下方面获得灵感:Validation 在搜索GWT验证示例时。。。你在哪里?,validation,gwt,celltable,Validation,Gwt,Celltable,作为后续行动 我正在尝试添加JSR-303验证支持。我在这里遵循了Koma的配置建议:(注意:我使用的是GWT2.4的内置验证,而不是GWT验证) 同样,为了得到一些重用,我制作了一对类,ValidatableInputCell和AbstractValidatableColumn。我从以下方面获得灵感: 让我们看看他们 public class ValidatableInputCell extends AbstractInputCell<String, ValidatableInp
public class ValidatableInputCell extends AbstractInputCell<String, ValidatableInputCell.ValidationData> {
interface Template extends SafeHtmlTemplates {
@Template("<input type=\"text\" value=\"{0}\" size=\"{1}\" style=\"{2}\" tabindex=\"-1\"></input>")
SafeHtml input(String value, String width, SafeStyles color);
}
private static Template template;
/**
* The error message to be displayed as a pop-up near the field
*/
private String errorMessage;
private static final int DEFAULT_INPUT_SIZE = 15;
/**
* Specifies the width, in characters, of the <input> element contained within this cell
*/
private int inputSize = DEFAULT_INPUT_SIZE;
public ValidatableInputCell() {
super("change", "keyup");
if (template == null) {
template = GWT.create(Template.class);
}
}
public void setInputSize(int inputSize) {
this.inputSize = inputSize;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = SafeHtmlUtils.htmlEscape(errorMessage);
}
@Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
// Ignore events that don't target the input.
final InputElement input = (InputElement) getInputElement(parent);
final Element target = event.getEventTarget().cast();
if (!input.isOrHasChild(target)) {
return;
}
final Object key = context.getKey();
final String eventType = event.getType();
if ("change".equals(eventType)) {
finishEditing(parent, value, key, valueUpdater);
} else if ("keyup".equals(eventType)) {
// Mark cell as containing a pending change
input.getStyle().setColor("blue");
ValidationData viewData = getViewData(key);
// Save the new value in the view data.
if (viewData == null) {
viewData = new ValidationData();
setViewData(key, viewData);
}
final String newValue = input.getValue();
viewData.setValue(newValue);
finishEditing(parent, newValue, key, valueUpdater);
// Update the value updater, which updates the field updater.
if (valueUpdater != null) {
valueUpdater.update(newValue);
}
}
}
@Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
final Object key = context.getKey();
ValidationData viewData = getViewData(key);
if (viewData != null && viewData.getValue().equals(value)) {
// Clear the view data if the value is the same as the current value.
clearViewData(key);
viewData = null;
}
/*
* If viewData is null, just paint the contents black. If it is non-null,
* show the pending value and paint the contents red if they are known to
* be invalid.
*/
final String pendingValue = viewData == null ? null : viewData.getValue();
final boolean invalid = viewData == null ? false : viewData.isInvalid();
final String color = pendingValue != null ? invalid ? "red" : "blue" : "black";
final SafeStyles safeColor = SafeStylesUtils.fromTrustedString("color: " + color + ";");
sb.append(template.input(pendingValue != null ? pendingValue : value, String.valueOf(inputSize), safeColor));
}
@Override
protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
final Element target = event.getEventTarget().cast();
if (getInputElement(parent).isOrHasChild(target)) {
finishEditing(parent, value, context.getKey(), valueUpdater);
} else {
super.onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
protected void finishEditing(Element parent, String value, Object key,
ValueUpdater<String> valueUpdater) {
final ValidationData viewData = getViewData(key);
final String pendingValue = viewData == null ? null : viewData.getValue();
final boolean invalid = viewData == null ? false : viewData.isInvalid();
if (invalid) {
final DecoratedPopupPanel errorMessagePopup = new DecoratedPopupPanel(true);
final VerticalPanel messageContainer = new VerticalPanel();
messageContainer.setWidth("200px");
final Label messageTxt = new Label(errorMessage, true);
messageTxt.setStyleName(UiResources.INSTANCE.style().error());
messageContainer.add(messageTxt);
errorMessagePopup.setWidget(messageContainer);
// Reposition the popup relative to input field
final int left = parent.getAbsoluteRight() + 25;
final int top = parent.getAbsoluteTop();
errorMessagePopup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
errorMessagePopup.setPopupPosition(left, top);
}
});
}
// XXX let user continue or force focus until value is valid? for now the former is implemented
super.finishEditing(parent, pendingValue, key, valueUpdater);
}
/**
* The ViewData used by {@link ValidatableInputCell}.
*/
static class ValidationData {
private boolean invalid;
private String value;
public String getValue() {
return value;
}
public boolean isInvalid() {
return invalid;
}
public void setInvalid(boolean invalid) {
this.invalid = invalid;
}
public void setValue(String value) {
this.value = value;
}
}
}
如果在onBrowserEvent中删除断点,我希望在每个按键笔划和/或单元格失去焦点后都会触发验证触发器。它永远不会被调用。我可以随意进入牢房。关于修复方法有什么线索吗
我早期的想法。。。a) AbstractValidableColumn#getFieldUpdater从未被调用,b)ValidableInputCell#onBrowserEvent或ValidableInputCell#render中的逻辑需要大修
最后,我希望看到违反约束的每个单元格旁边都会出现一个弹出窗口,当然也希望看到应用了适当的颜色。我不清楚为什么会从
generatePriceColumn
返回HasCell
,因为实际上任何东西都不能使用它,除了CompositeCell
——可能您正试图将所有这些都打包到一个更大的单元格中。在提问之前,你可以考虑在将来进一步细分你的例子,这个问题可能会变得清晰。
我更改了“column”创建代码,因此它实际上返回了一个列—这意味着将AbstractValidatableColumn更改为扩展列。在这个过程中,我注意到您正在重写getFieldUpdater,而没有修改底层字段,这将阻止列的其他内部部分在查找该字段时工作。因此,我最初的实验是正确地使用validableInputCell.onBrowserEvent
的keyup案例,但是没有ValueUpdater
实例可供使用,因为FieldUpdater
列中为空
在这一点上,我没有连接的验证逻辑正在被调用——从GWT 2.4.0开始,它仍然在每个类中被标记为“实验性”,并且不用于生产代码,因此我给它一个通行证,直到2.5.0左右,当粗糙的边缘被舍入时。如果我要继续(如果你有问题的话),我会从项目开始-让它工作,然后窃取细节,直到我的工作也一样
其他一些意见:
不要扩展类来添加功能,除非您希望/允许该类的任何使用者像使用子类一样使用它。在这种情况下很难说,但是generatePriceColumn
似乎位于CellTable
子类上,该子类
CellTable
方法-其他关注列的方法实际上是添加列而不是返回列CellTable
(因为这是您的子类),而该方法将非常适合于AbstractCellTable
子类,如DataTable
,一个较新的CellTable
addPriceColumn(…)
,让它使用一个列并将其添加到列表中,要么将其作为子类列保留,要么完全作为实用方法保留。我最后的AbstractValidationColumn没有太多理由成为一个子类,实际上只是一个方便的Column构造函数:
public abstract class AbstractValidatableColumn<T> extends Column<T, String> {
public AbstractValidatableColumn(int inputSize, final AbstractCellTable<T> table) {
super(new ValidatableInputCell());
((ValidatableInputCell) getCell()).setInputSize(inputSize);
setFieldUpdater(new FieldUpdater<T, String>() {
public void update(int index, T dto, String value) {
final Set<ConstraintViolation<T>> violations = validate(dto);
final ValidationData viewData = getCell().getViewData(dto);
if (!violations.isEmpty()) { // invalid
final StringBuffer errorMessage = new StringBuffer();
for (final ConstraintViolation<T> constraintViolation : violations) {
errorMessage.append(constraintViolation.getMessage());
}
viewData.setInvalid(true);
getCell().setErrorMessage(errorMessage.toString());
table.redraw();
} else { // valid
viewData.setInvalid(false);
getCell().setErrorMessage(null);
doUpdate(index, dto, value);
}
}
});
}
@Override
public ValidatableInputCell getCell() {
return (ValidatableInputCell)super.getCell();
}
protected abstract void doUpdate(int index, T dto, String value);
protected Set<ConstraintViolation<T>> validate(T dto) {
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Set<ConstraintViolation<T>> violations = validator.validate(dto);
return violations;
}
}
公共抽象类AbstractValidatableColumn扩展列{
公共AbstractValidatableColumn(int inputSize,最终AbstractCellTable表){
super(新的ValidatableInputCell());
((ValidatableInputCell)getCell()).setInputSize(inputSize);
setFieldUpdater(新的FieldUpdater(){
公共void更新(int索引、T dto、字符串值){
最终设置冲突=验证(dto);
最终验证数据viewData=getCell().getViewData(dto);
如果(!inflictions.isEmpty()){//无效
final StringBuffer errorMessage=新StringBuffer();
对于(最终约束强制约束强制约束:违反){
errorMessage.append(constraintViolation.getMessage());
}
viewData.setInvalid(true);
getCell().setErrorMessage(errorMessage.toString());
表1.redraw();
}else{//有效
viewData.setInvalid(false);
getCell().setErrorMessage(null);
doUpdate(索引、dto、值);
}
}
});
}
@凌驾
public ValidatableInputCell getCell(){
返回(ValidatableInputCell)super.getCell();
}
受保护的抽象void doUpdate(int索引、T dto、字符串值);
受保护集验证(T dto){
最终验证器验证器=Validation.buildDefaultValidatorFactory().getValidator();
最终设置冲突=validator.validate(dto);
返回违规行为;
}
}
FieldUpdater是这里有趣的部分,这是应该重点关注的,并留下尽可能多的其他部分供重用。这将允许任何单元格在准备就绪时运行自己的ValueUpdater—可能没有您希望的那么频繁,但它通常会使事情更易于快速使用。制作一个FieldUpdater impl来包装另一个FieldUpdater,它可以特定于在这种情况下更改的任何字段
我认为这里潜藏着另一个bug,如果您单独测试column/fieldupdater,可能会出现这个bug——直到验证运行之后,新值才应用于t类型的bean,因此正在使用旧的有效值验证bean<需要更快地调用code>doUpdate
最后,我鼓励大家在学习的过程中尽量简化自己的例子——有些夸张
protected HasCell<ReserveOfferDTO, String> generatePriceColumn(DisplayMode currentDisplayMode) {
HasCell<ReserveOfferDTO, String> priceColumn;
if (isInEditMode(currentDisplayMode)) {
priceColumn = new AbstractValidatableColumn<ReserveOfferDTO>(5, this) {
@Override
public String getValue(ReserveOfferDTO reserveOffer) {
return obtainPriceValue(reserveOffer);
}
@Override
protected void doUpdate(int index, ReserveOfferDTO reserveOffer, String value) {
// number format exceptions should be caught and handled by event bus's handle method
final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
reserveOffer.setPrice(price);
}
};
} else {
priceColumn = new Column<ReserveOfferDTO, String>(new TextCell()) {
@Override
public String getValue(ReserveOfferDTO reserveOffer) {
return obtainPriceValue(reserveOffer);
}
};
}
return priceColumn;
}
public class ReserveOfferDTO extends DateComparable implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull @Digits(integer=6, fraction=2)
private BigDecimal price;
@NotNull @Digits(integer=6, fraction=2)
private BigDecimal fixedMW;
private String dispatchStatus;
private String resourceName;
private String dateTime;
private String marketType;
private String productType;
...
}
public abstract class AbstractValidatableColumn<T> extends Column<T, String> {
public AbstractValidatableColumn(int inputSize, final AbstractCellTable<T> table) {
super(new ValidatableInputCell());
((ValidatableInputCell) getCell()).setInputSize(inputSize);
setFieldUpdater(new FieldUpdater<T, String>() {
public void update(int index, T dto, String value) {
final Set<ConstraintViolation<T>> violations = validate(dto);
final ValidationData viewData = getCell().getViewData(dto);
if (!violations.isEmpty()) { // invalid
final StringBuffer errorMessage = new StringBuffer();
for (final ConstraintViolation<T> constraintViolation : violations) {
errorMessage.append(constraintViolation.getMessage());
}
viewData.setInvalid(true);
getCell().setErrorMessage(errorMessage.toString());
table.redraw();
} else { // valid
viewData.setInvalid(false);
getCell().setErrorMessage(null);
doUpdate(index, dto, value);
}
}
});
}
@Override
public ValidatableInputCell getCell() {
return (ValidatableInputCell)super.getCell();
}
protected abstract void doUpdate(int index, T dto, String value);
protected Set<ConstraintViolation<T>> validate(T dto) {
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Set<ConstraintViolation<T>> violations = validator.validate(dto);
return violations;
}
}
/**
* A {@link Column} implementation that encapsulates a {@link ValidatableInputCell}.
* Performs JSR-303 validation on a field (or nested field) of the type.
* @author cphillipson
*
* @param <T> the type
* @param <O> the owning type of the field to be validated; in many cases T may have only primitive or wrapper types, therefore O will be the same type as T
*/
public abstract class AbstractValidatableColumn<T, O> extends Column<T, String> {
/**
* Preferred constructor.
* Allows for definition of tabIndex but uses a default for the input cell size.
* @param tabIndex the <code>tabindex</code> attribute's value for the input cell
* @param table the grid instance
*/
public AbstractValidatableColumn(int tabIndex, final AbstractHasData<T> table) {
this(App.INSTANCE.defaultValidatableInputCellSize(), tabIndex, table);
}
/**
* Overloaded constructor.
* Allows for definition of tabIndex and allows for an override to the default for the input cell size.
* @param inputSize the <code>size</code> attribute's value for the input cell
* @param tabIndex the <code>tabindex</code> attribute's value for the input cell
* @param table the grid instance
*/
public AbstractValidatableColumn(int inputSize, int tabIndex, final AbstractHasData<T> table) {
super(new ValidatableInputCell());
getCell().setInputSize(inputSize);
getCell().setTabIndex(tabIndex);
init(table);
}
// meat and potatoes
private void init(final AbstractHasData<T> table) {
setFieldUpdater(new FieldUpdater<T, String>() {
@Override
public void update(int index, T dto, String newValue) {
final ConversionResult cr = attemptValueConversion(newValue);
final ValidationData viewData = getCell().getViewData(dto);
if (cr.wasConvertedSuccessfully()) {
final Set<ConstraintViolation<O>> violations = validate(cr.getValue());
if (!violations.isEmpty()) { // invalid
final StringBuffer errorMessage = new StringBuffer();
for (final ConstraintViolation<O> constraintViolation : violations) {
errorMessage.append(constraintViolation.getMessage());
}
viewData.setInvalid(true);
getCell().setErrorMessage(errorMessage.toString());
} else { // valid
viewData.setInvalid(false);
getCell().setErrorMessage("");
doUpdate(index, dto, newValue);
}
} else { // conversion exception
viewData.setInvalid(true);
getCell().setErrorMessage(UiMessages.INSTANCE.improper_input_format());
}
}
});
}
/**
* Attempts conversion of a String value into another type
* Instances are responsible for the conversion logic as it may vary from type to type
* @param value a String value to be converted into an owning class's property type
* @return a ConversionResult
*/
protected abstract ConversionResult attemptValueConversion(String value);
@Override
public ValidatableInputCell getCell() {
return (ValidatableInputCell) super.getCell();
}
/**
* Template method for updating a field (or nested field) value within a DTO
* @param index the row index for the instance of the DTO within the grid
* @param dto the object whose field we wish to update
* @param value the new value that will be set on a field (or nested field) of the DTO
*/
protected abstract void doUpdate(int index, T dto, String value);
/**
* Template method for specifying the property name of an owning class
* @return the field name of the owning class whose value is to be updated
*/
protected abstract String getPropertyName();
/**
* Template method for specifying the owning class
* @return the owning class of the field whose value is to be updated
*/
protected abstract Class<O> getPropertyOwner();
/**
* Validates a value against a set of constraints (i.e., JSR-303 annotations on a field)
* @param newValue the value to be validated
* @return the set of constraint violations induced by an inappropriate value
*/
protected Set<ConstraintViolation<O>> validate(Object newValue) {
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Set<ConstraintViolation<O>> violations = validator.validateValue(getPropertyOwner(), getPropertyName(), newValue);
return violations;
}
}
/**
* <p>A cell that will update its styling and provide feedback upon a validation constraint violation.</p>
* <p>Implementation based upon GWT Showcase's <a href="http://gwt.google.com/samples/Showcase/Showcase.html#!CwCellValidation">Cell Validation</a> example.</p>
* @author cphillipson
*
*/
public class ValidatableInputCell extends AbstractInputCell<String, ValidatableInputCell.ValidationData> {
interface Template extends SafeHtmlTemplates {
@Template("<input type=\"text\" value=\"{0}\" size=\"{1}\" style=\"{2}\" tabindex=\"{3}\"></input>")
SafeHtml input(String value, String width, SafeStyles color, String tabIndex);
}
private static Template template;
/**
* The error message to be displayed as a pop-up near the field
*/
private String errorMessage;
private static final int DEFAULT_INPUT_SIZE = App.INSTANCE.defaultValidatableInputCellSize();
/**
* Specifies the width, in characters, of the <input> element contained within this cell
*/
private int inputSize = DEFAULT_INPUT_SIZE;
/**
* Specifies the tab index for this cell
*/
private int tabIndex = -1;
public ValidatableInputCell() {
// since onBrowserEvent method is overridden, we must register all events that handled in overridden method impl
super("change", "keyup", "focus", "blur", "keydown");
if (template == null) {
template = GWT.create(Template.class);
}
}
public void setInputSize(int inputSize) {
this.inputSize = inputSize;
}
public void setTabIndex(int index) {
tabIndex = index;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = SafeHtmlUtils.fromSafeConstant(errorMessage).asString();
}
@Override
public void onBrowserEvent(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
final InputElement input = (InputElement) getInputElement(parent);
final Object key = context.getKey();
final String eventType = event.getType();
if ("keyup".equals(eventType)) {
ValidationData viewData = getViewData(key);
// Save the new value in the view data.
if (viewData == null) {
viewData = new ValidationData();
setViewData(key, viewData);
}
final String newValue = input.getValue();
viewData.setValue(newValue);
finishEditing(parent, newValue, key, valueUpdater);
}
}
@Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
// Get the view data.
final Object key = context.getKey();
ValidationData viewData = getViewData(key);
if (viewData != null && viewData.getValue().equals(value)) {
// Clear the view data if the value is the same as the current value.
clearViewData(key);
viewData = null;
}
/*
* If viewData is null, just paint the contents black. If it is non-null,
* show the pending value and paint the contents red if they are known to
* be invalid.
*/
final String pendingValue = viewData == null ? null : viewData.getValue();
final boolean invalid = viewData == null ? false : viewData.isInvalid();
final String color = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextColor() : App.INSTANCE.pendingCellInputTextColor() : App.INSTANCE.defaultCellInputTextColor();
final String backgroundColor = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextBackgroundColor() : App.INSTANCE.pendingCellInputTextBackgroundColor() : App.INSTANCE.defaultCellInputTextBackgroundColor();
final SafeStyles style = SafeStylesUtils.fromTrustedString("color: " + color + "; background-color: " + backgroundColor + ";");
sb.append(template.input(pendingValue != null ? pendingValue : value, String.valueOf(inputSize), style, String.valueOf(tabIndex)));
}
/*
@Override
protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
final Element target = event.getEventTarget().cast();
if (getInputElement(parent).isOrHasChild(target)) {
finishEditing(parent, value, context.getKey(), valueUpdater);
} else {
super.onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
*/
@Override
protected void onEnterKeyDown(Context context, Element parent, String value,
NativeEvent event, ValueUpdater<String> valueUpdater) {
// do nothing
}
@Override
protected void finishEditing(Element parent, String value, Object key,
ValueUpdater<String> valueUpdater) {
// Update the value updater, which updates the field updater.
if (valueUpdater != null) {
valueUpdater.update(value);
}
final InputElement input = (InputElement) getInputElement(parent);
final ValidationData viewData = getViewData(key);
/*
* If viewData is null, just paint the contents black. If it is non-null,
* show the pending value and paint the contents red if they are known to
* be invalid.
*/
final String pendingValue = viewData == null ? null : viewData.getValue();
final boolean invalid = viewData == null ? false : viewData.isInvalid();
final String color = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextColor() : App.INSTANCE.pendingCellInputTextColor() : App.INSTANCE.defaultCellInputTextColor();
final String backgroundColor = pendingValue != null ? invalid ? App.INSTANCE.invalidCellInputTextBackgroundColor() : App.INSTANCE.pendingCellInputTextBackgroundColor() : App.INSTANCE.defaultCellInputTextBackgroundColor();
input.getStyle().setColor(color);
input.getStyle().setBackgroundColor(backgroundColor);
if (invalid) {
final DecoratedPopupPanel errorMessagePopup = new DecoratedPopupPanel(true);
final FlowPanel messageContainer = new FlowPanel();
messageContainer.setWidth(App.INSTANCE.errorMessagePopupWidth());
final Label messageTxt = new Label(errorMessage, true);
messageTxt.setStyleName(UiResources.INSTANCE.style().error());
messageContainer.add(messageTxt);
errorMessagePopup.setWidget(messageContainer);
// Reposition the popup relative to input field
final int left = parent.getAbsoluteRight() +5;
final int top = parent.getAbsoluteTop() - 5;
errorMessagePopup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
errorMessagePopup.setPopupPosition(left, top);
}
});
}
}
/**
* The ViewData used by {@link ValidatableInputCell}.
*/
static class ValidationData {
private boolean invalid;
private String value;
public String getValue() {
return value;
}
public boolean isInvalid() {
return invalid;
}
public void setInvalid(boolean invalid) {
this.invalid = invalid;
}
public void setValue(String value) {
this.value = value;
}
}
}
/**
* A variant of {@link AbstractValidatableColumn} that works with {@link BigDecimal} field types.
* @author cphillipson
*
* @param <T> the type
* @param <O> the owning type of the field to be validated; in many cases T may have only primitive or wrapper types, therefore O will be the same type as T
*/
public abstract class BigDecimalValidatableColumn<T, O> extends AbstractValidatableColumn<T, O> {
public BigDecimalValidatableColumn(int tabIndex, AbstractHasData table) {
super(tabIndex, table);
}
public BigDecimalValidatableColumn(int inputSize, int tabIndex, final AbstractHasData<T> table) {
super(inputSize, tabIndex, table);
}
@Override
protected ConversionResult attemptValueConversion(String value) {
return doConversion(value);
}
public static ConversionResult doConversion(String value) {
ConversionResult result = null;
try {
final Double dblValue = Double.valueOf(value);
final BigDecimal convertedValue = BigDecimal.valueOf(dblValue);
result = ConversionResult.converted(convertedValue);
} catch (final NumberFormatException nfe) {
result = ConversionResult.not_converted();
}
return result;
}
}
/**
* An attempted conversion result.
* Returns both the converted value (from <code>String</code>) and whether or not the conversion was successful.
* E.g., if you tried to convert from a <code>String</code> to a <code>Number</code>, in the failure case this would result in a <code>NumberFormatException</code>.
* On failure, the boolean would be false and the value would be null.
* On success, the boolean would be true and the value would be of the type needed to continue validation against a set of constraints
* @author cphillipson
*
*/
public class ConversionResult {
private Object value;
private boolean convertedSuccessfully;
private ConversionResult () {}
/**
* Use this method when a successful conversion is made to return a result
* @param value the convertedValue
* @return the result of the conversion containing the converted value and a success flag
*/
public static ConversionResult converted(Object value) {
final ConversionResult result = new ConversionResult();
result.setConvertedSuccessfully(true);
result.setValue(value);
return result;
}
/**
* Use this method when an attempt to convert a String value failed
* @return the result of a failed conversion
*/
public static ConversionResult not_converted() {
return new ConversionResult();
}
private void setValue(Object value) {
this.value = value;
}
public Object getValue() {
return value;
}
private void setConvertedSuccessfully(boolean flag) {
convertedSuccessfully = flag;
}
public boolean wasConvertedSuccessfully() {
return convertedSuccessfully;
}
}
new BigDecimalValidatableColumn<EnergyOfferDTO, OfferPriceMwPairDTO>(nextTabIndex(), getGrid()) {
@Override
public String getValue(EnergyOfferDTO energyOffer) {
return obtainPriceValue(colIndex, energyOffer, false);
}
@Override
public void doUpdate(int index, EnergyOfferDTO energyOffer, String value) {
if (value != null && !value.isEmpty()) {
// number format exceptions should be caught and handled by event bus's handle method
final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);
final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getCurve();
final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
if (offerPriceMwPairDTO == null) { // we have a new price value
newOfferPriceMwPair.setPrice(price);
offerPriceCurve.add(newOfferPriceMwPair);
} else {
offerPriceMwPairDTO.setPrice(price);
}
}
}
@Override
protected String getPropertyName() {
return "price";
}
@Override
protected Class<OfferPriceMwPairDTO> getPropertyOwner() {
return OfferPriceMwPairDTO.class;
}
};