From 19a3e00e013bcc577ebeb32f2ac4bff97fd2a476 Mon Sep 17 00:00:00 2001 From: Raul Bob Date: Tue, 17 Mar 2026 00:38:37 +0100 Subject: [PATCH 1/3] #13883 - Fixed IGRA inputs value change listeners - Refactored duplicated listeners for IGRA inputs into two listeners - Fixed error caused by locale conversions with IGRA numeric inputs --- .../sormas/ui/samples/PathogenTestForm.java | 503 +++++++----------- 1 file changed, 201 insertions(+), 302 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java index 7ac59a0bdb4..17ea1228c63 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -40,7 +41,11 @@ import org.slf4j.LoggerFactory; import com.vaadin.ui.Label; +import com.vaadin.v7.data.Property; +import com.vaadin.v7.data.fieldgroup.BeanFieldGroup; +import com.vaadin.v7.data.util.BeanItem; import com.vaadin.v7.data.util.converter.Converter; +import com.vaadin.v7.data.util.converter.ConverterUtil; import com.vaadin.v7.ui.AbstractSelect.ItemCaptionMode; import com.vaadin.v7.ui.CheckBox; import com.vaadin.v7.ui.ComboBox; @@ -624,317 +629,25 @@ protected void addFields() { addFields( FieldConfiguration.builder(PathogenTestDto.TUBE_NIL) .validationMessageProperty(Validations.onlyNumbersAllowed) - .valueChangeListener(e -> { - final String tubeNilFieldValue = (String) e.getProperty().getValue(); - final NullableOptionGroup tubeNilGt10Field = getField(PathogenTestDto.TUBE_NIL_GT10); - final Float tubeNilValue = getValue().getTubeNil(); - final Boolean tubeNilGt10Value = getValue().getTubeNilGT10(); - - // we are called for a new entry - if(tubeNilValue == null - && tubeNilGt10Value == null - && tubeNilFieldValue == null - && tubeNilGt10Field.getNullableValue() == null) { - tubeNilGt10Field.select(false); - return; - } - - if(tubeNilFieldValue == null) { - tubeNilGt10Field.select(false); - return; - } - Float tubeNilNewValue = null; - try { - tubeNilNewValue = Float.parseFloat(tubeNilFieldValue); - } catch (NumberFormatException ex) { - // if it is not a number we clear the field - getField(PathogenTestDto.TUBE_NIL).clear(); - tubeNilGt10Field.select(false); - return; - } - // now we have a current and old value - if(tubeNilNewValue > 10) { - tubeNilGt10Field.select(true); - } else { - tubeNilGt10Field.select(false); - } - }) + .valueChangeListener(new TuberculosisIGRAInputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_NIL,PathogenTestDto.TUBE_NIL_GT10)) .build(), FieldConfiguration.builder(PathogenTestDto.TUBE_AG_TB1) .validationMessageProperty(Validations.onlyNumbersAllowed) - .valueChangeListener(e -> { - final String tubeAgTb1FieldValue = (String) e.getProperty().getValue(); - final NullableOptionGroup tubeAgTb1Gt10Field = getField(PathogenTestDto.TUBE_AG_TB1_GT10); - final Float tubeAgTb1Value = getValue().getTubeAgTb1(); - final Boolean tubeAgTb1Gt10Value = getValue().getTubeAgTb1GT10(); - - // we are called for a new entry - if(tubeAgTb1Value == null - && tubeAgTb1Gt10Value == null - && tubeAgTb1FieldValue == null - && tubeAgTb1Gt10Field.getNullableValue() == null) { - tubeAgTb1Gt10Field.select(false); - return; - } - - if(tubeAgTb1FieldValue == null) { - tubeAgTb1Gt10Field.select(false); - return; - } - Float tubeAgTb1NewValue = null; - try { - tubeAgTb1NewValue = Float.parseFloat(tubeAgTb1FieldValue); - } catch (NumberFormatException ex) { - // if it is not a number we clear the field - getField(PathogenTestDto.TUBE_AG_TB1).clear(); - tubeAgTb1Gt10Field.select(false); - return; - } - // now we have a current and old value - if(tubeAgTb1NewValue > 10) { - tubeAgTb1Gt10Field.select(true); - } else { - tubeAgTb1Gt10Field.select(false); - } - }) - .build(), + .valueChangeListener(new TuberculosisIGRAInputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_AG_TB1,PathogenTestDto.TUBE_AG_TB1_GT10)).build(), FieldConfiguration.builder(PathogenTestDto.TUBE_AG_TB2) .validationMessageProperty(Validations.onlyNumbersAllowed) - .valueChangeListener(e -> { - final String tubeAgTb2FieldValue = (String) e.getProperty().getValue(); - final NullableOptionGroup tubeAgTb2Gt10Field = getField(PathogenTestDto.TUBE_AG_TB2_GT10); - final Float tubeAgTb2Value = getValue().getTubeAgTb2(); - final Boolean tubeAgTb2Gt10Value = getValue().getTubeAgTb2GT10(); - - // we are called for a new entry - if(tubeAgTb2Value == null - && tubeAgTb2Gt10Value == null - && tubeAgTb2FieldValue == null - && tubeAgTb2Gt10Field.getNullableValue() == null) { - tubeAgTb2Gt10Field.select(false); - return; - } - - if(tubeAgTb2FieldValue == null) { - tubeAgTb2Gt10Field.select(false); - return; - } - Float tubeAgTb2NewValue = null; - try { - tubeAgTb2NewValue = Float.parseFloat(tubeAgTb2FieldValue); - } catch (NumberFormatException ex) { - // if it is not a number we clear the field - getField(PathogenTestDto.TUBE_AG_TB2).clear(); - tubeAgTb2Gt10Field.select(false); - return; - } - // now we have a current and old value - if(tubeAgTb2NewValue > 10) { - tubeAgTb2Gt10Field.select(true); - } else { - tubeAgTb2Gt10Field.select(false); - } - }) - .build(), + .valueChangeListener(new TuberculosisIGRAInputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_AG_TB2,PathogenTestDto.TUBE_AG_TB2_GT10)).build(), FieldConfiguration.builder(PathogenTestDto.TUBE_MITOGENE) .validationMessageProperty(Validations.onlyNumbersAllowed) - .valueChangeListener(e -> { - final String tubeMitogeneFieldValue = (String) e.getProperty().getValue(); - final NullableOptionGroup tubeMitogeneGt10Field = getField(PathogenTestDto.TUBE_MITOGENE_GT10); - final Float tubeMitogeneValue = getValue().getTubeMitogene(); - final Boolean tubeMitogeneGt10Value = getValue().getTubeMitogeneGT10(); - - // we are called for a new entry - if(tubeMitogeneValue == null - && tubeMitogeneGt10Value == null - && tubeMitogeneFieldValue == null - && tubeMitogeneGt10Field.getNullableValue() == null) { - tubeMitogeneGt10Field.select(false); - return; - } - - if(tubeMitogeneFieldValue == null) { - tubeMitogeneGt10Field.select(false); - return; - } - Float tubeMitogeneNewValue = null; - try { - tubeMitogeneNewValue = Float.parseFloat(tubeMitogeneFieldValue); - } catch (NumberFormatException ex) { - // if it is not a number we clear the field - getField(PathogenTestDto.TUBE_MITOGENE).clear(); - tubeMitogeneGt10Field.select(false); - return; - } - // now we have a current and old value - if(tubeMitogeneNewValue > 10) { - tubeMitogeneGt10Field.select(true); - } else { - tubeMitogeneGt10Field.select(false); - } - }) - .build()); + .valueChangeListener(new TuberculosisIGRAInputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_MITOGENE,PathogenTestDto.TUBE_MITOGENE_GT10)).build()); //@formatter:on //@formatter:off addFields( - FieldConfiguration.builder(PathogenTestDto.TUBE_NIL_GT10).valueChangeListener(event -> { - final Object propertySingleValue = event.getProperty().getValue() instanceof Collection - ? ((Collection) event.getProperty().getValue()).stream().findFirst().orElse(null) - : event.getProperty().getValue(); - final Float tubeNilValue = getValue().getTubeNil(); - - // we are called for a new entry or initial calls - if(propertySingleValue == null && tubeNilValue == null) { - final NullableOptionGroup tubeNilGt10Field = getField(PathogenTestDto.TUBE_NIL_GT10); - tubeNilGt10Field.select(false); - return; - } - final boolean checked = Boolean.TRUE.equals(propertySingleValue); - final Field tubeNilField = getField(PathogenTestDto.TUBE_NIL); - - final String tubeNilFieldValue = (String) tubeNilField.getValue(); - if(tubeNilFieldValue == null) { - // if there is no value we don't care about the checkbox value - return; - } - Float tubeNilNewValue = null; - try { - tubeNilNewValue = Float.valueOf(tubeNilFieldValue); - } catch (NumberFormatException ex) { - // if it's not a number we don't care about the value - tubeNilField.clear(); - return; - } - // if the checkbox is checked and the value is less than 10, we clear the field - if (checked && tubeNilNewValue < 10) { - tubeNilField.clear(); - return; - } - // if the checkbox is unchecked and the value is greater than or equal to 10, we clear the field - if(!checked && tubeNilNewValue >= 10) { - tubeNilField.clear(); - return; - } - }).build(), - FieldConfiguration.builder(PathogenTestDto.TUBE_AG_TB1_GT10).valueChangeListener(event -> { - final Object propertySingleValue = event.getProperty().getValue() instanceof Collection - ? ((Collection) event.getProperty().getValue()).stream().findFirst().orElse(null) - : event.getProperty().getValue(); - final Float tubeAgTb1Value = getValue().getTubeAgTb1(); - - // we are called for a new entry or initial calls - if(propertySingleValue == null && tubeAgTb1Value == null) { - final NullableOptionGroup tubeAgTb1Gt10Field = getField(PathogenTestDto.TUBE_AG_TB1_GT10); - tubeAgTb1Gt10Field.select(false); - return; - } - final boolean checked = Boolean.TRUE.equals(propertySingleValue); - final Field tubeAgTb1Field = getField(PathogenTestDto.TUBE_AG_TB1); - - final String tubeAgTb1FieldValue = (String) tubeAgTb1Field.getValue(); - if(tubeAgTb1FieldValue == null) { - // if there is no value we don't care about the checkbox value - return; - } - Float tubeAgTb1NewValue = null; - try { - tubeAgTb1NewValue = Float.valueOf(tubeAgTb1FieldValue); - } catch (NumberFormatException ex) { - // if it's not a number we don't care about the value - tubeAgTb1Field.clear(); - return; - } - // if the checkbox is checked and the value is less than or equal to 10, we clear the field - if (checked && tubeAgTb1NewValue <= 10) { - tubeAgTb1Field.clear(); - return; - } - // if the checkbox is unchecked and the value is greater than 10, we clear the field - if(!checked && tubeAgTb1NewValue > 10) { - tubeAgTb1Field.clear(); - return; - } - }).build(), - FieldConfiguration.builder(PathogenTestDto.TUBE_AG_TB2_GT10).valueChangeListener(event -> { - final Object propertySingleValue = event.getProperty().getValue() instanceof Collection - ? ((Collection) event.getProperty().getValue()).stream().findFirst().orElse(null) - : event.getProperty().getValue(); - final Float tubeAgTb2Value = getValue().getTubeAgTb2(); - - // we are called for a new entry or initial calls - if(propertySingleValue == null && tubeAgTb2Value == null) { - final NullableOptionGroup tubeAgTb2Gt10Field = getField(PathogenTestDto.TUBE_AG_TB2_GT10); - tubeAgTb2Gt10Field.select(false); - return; - } - final boolean checked = Boolean.TRUE.equals(propertySingleValue); - final Field tubeAgTb2Field = getField(PathogenTestDto.TUBE_AG_TB2); - - final String tubeAgTb2FieldValue = (String) tubeAgTb2Field.getValue(); - if(tubeAgTb2FieldValue == null) { - // if there is no value we don't care about the checkbox value - return; - } - Float tubeAgTb2NewValue = null; - try { - tubeAgTb2NewValue = Float.valueOf(tubeAgTb2FieldValue); - } catch (NumberFormatException ex) { - // if it's not a number we don't care about the value - tubeAgTb2Field.clear(); - return; - } - // if the checkbox is checked and the value is less than or equal to 10, we clear the field - if (checked && tubeAgTb2NewValue <= 10) { - tubeAgTb2Field.clear(); - return; - } - // if the checkbox is unchecked and the value is greater than 10, we clear the field - if(!checked && tubeAgTb2NewValue > 10) { - tubeAgTb2Field.clear(); - return; - } - }).build(), - FieldConfiguration.builder(PathogenTestDto.TUBE_MITOGENE_GT10).valueChangeListener(event -> { - final Object propertySingleValue = event.getProperty().getValue() instanceof Collection - ? ((Collection) event.getProperty().getValue()).stream().findFirst().orElse(null) - : event.getProperty().getValue(); - final Float tubeMitogeneValue = getValue().getTubeMitogene(); - - // we are called for a new entry or initial calls - if(propertySingleValue == null && tubeMitogeneValue == null) { - final NullableOptionGroup tubeMitogeneGt10Field = getField(PathogenTestDto.TUBE_MITOGENE_GT10); - tubeMitogeneGt10Field.select(false); - return; - } - final boolean checked = Boolean.TRUE.equals(propertySingleValue); - final Field tubeMitogeneField = getField(PathogenTestDto.TUBE_MITOGENE); - - final String tubeMitogeneFieldValue = (String) tubeMitogeneField.getValue(); - if(tubeMitogeneFieldValue == null) { - // if there is no value we don't care about the checkbox value - return; - } - Float tubeMitogeneNewValue = null; - try { - tubeMitogeneNewValue = Float.valueOf(tubeMitogeneFieldValue); - } catch (NumberFormatException ex) { - // if it's not a number we don't care about the value - tubeMitogeneField.clear(); - return; - } - // if the checkbox is checked and the value is less than or equal to 10, we clear the field - if (checked && tubeMitogeneNewValue <= 10) { - tubeMitogeneField.clear(); - return; - } - // if the checkbox is unchecked and the value is greater than 10, we clear the field - if(!checked && tubeMitogeneNewValue > 10) { - tubeMitogeneField.clear(); - return; - } - }).build() - ); + FieldConfiguration.builder(PathogenTestDto.TUBE_NIL_GT10).valueChangeListener(new TuberculosisIGRAGT10InputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_NIL_GT10,PathogenTestDto.TUBE_NIL)).build(), + FieldConfiguration.builder(PathogenTestDto.TUBE_AG_TB1_GT10).valueChangeListener(new TuberculosisIGRAGT10InputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_AG_TB1_GT10,PathogenTestDto.TUBE_AG_TB1)).build(), + FieldConfiguration.builder(PathogenTestDto.TUBE_AG_TB2_GT10).valueChangeListener(new TuberculosisIGRAGT10InputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_AG_TB2_GT10,PathogenTestDto.TUBE_AG_TB2)).build(), + FieldConfiguration.builder(PathogenTestDto.TUBE_MITOGENE_GT10).valueChangeListener(new TuberculosisIGRAGT10InputValueChangeListener(getFieldGroup(), PathogenTestDto.TUBE_MITOGENE_GT10,PathogenTestDto.TUBE_MITOGENE)).build()); //@formatter:on setVisibleClear( @@ -1276,11 +989,197 @@ protected void addFields() { || isVisibleAllowed(PathogenTestDto.PRESCRIBER_COUNTRY)); } - static class TestTypeValueChangeListener implements ValueChangeListener { + /** + * This class is to be used for the Tuberculosis IGRA input value change listeners. + * It will check/uncheck the Tuberculosis IGRA greater than 10 checkbox dependiong on the value of the input field. + *

+ * Note: ideally a custom component should be used for both fields, to avoid potential race conditions between the two listeners. + */ + protected static class TuberculosisIGRAInputValueChangeListener implements ValueChangeListener { + + private final String igraInputFieldId; + private final String igraGT10FieldId; + private final BeanFieldGroup fieldGroup; + + public TuberculosisIGRAInputValueChangeListener(BeanFieldGroup fg, String igraInputFieldId, String igraGT10FieldId) { + this.igraInputFieldId = igraInputFieldId; + this.igraGT10FieldId = igraGT10FieldId; + this.fieldGroup = fg; + } + + @Override + public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { + + final Field igraInputField = fieldGroup.getField(igraInputFieldId); + + if (igraInputField == null) { + return; + } + + final BeanItem beanItemDataSource = fieldGroup.getItemDataSource(); + + // the input field is always a TextField with a String as value + // we need to make a hard assumtion that the input field value is a Float + + // we check to see if the model property is numeric + // the model at this point will not be updated, so we only check type + final Property igraValueProp = beanItemDataSource.getItemProperty(igraInputFieldId); + + if (!Number.class.isAssignableFrom(igraValueProp.getType())) { + // we will not deal with non-numeric values + return; + } + + // we know that the model property is numeric + // we could get the original value with: igraValueProp.getValue(); + + // we need to convert the value to number + // and we need to do it locale aware and need to finagle with types + @SuppressWarnings({ + "unchecked", + "rawtypes" }) + final Number igraNewValue = igraInputField.getValue() == null + ? null + : (Number) ConverterUtil.getConverter(igraInputField.getType(), (Class) igraValueProp.getType(), null /* current session */) + .convertToModel(igraInputField.getValue(), igraValueProp.getType(), null /* current locale */); + + final Boolean checked = igraNewValue == null ? null : igraNewValue.floatValue() > 10; + + // now we need to set the value of the GT10 field + @SuppressWarnings("unchecked") + final Field igraGT10Field = (Field) fieldGroup.getField(igraGT10FieldId); + if (igraGT10Field == null) { + // if we can't find the field, we don't care + return; + } + + // lets make sure the property is a boolean + final Property igraGT10Prop = beanItemDataSource.getItemProperty(igraGT10FieldId); + if (igraGT10Prop == null || !Boolean.class.isAssignableFrom(igraGT10Prop.getType())) { + // if we can't find the property, or we can't set it we don't care + return; + } + + // now field is supposed to be a boolean + // booleans come in two flavors: collection based and primitive + final boolean isCollection = Collection.class.isAssignableFrom(igraGT10Field.getType()); + + if (!isCollection) { + // primitive booleans are easy + final boolean currentChecked = Boolean.TRUE.equals(igraGT10Field.getValue()); + if (checked != null && checked != currentChecked) { + igraGT10Field.setValue(checked); + } + } else { + // well have to do it the hard way + final Collection currentSet = (Collection) igraGT10Field.getValue(); + final boolean currentChecked = currentSet != null && !currentSet.isEmpty() && currentSet.contains(Boolean.TRUE); + if (checked != null && checked != currentChecked) { + final HashSet set = new HashSet<>(); + set.add(checked); + igraGT10Field.setValue(set); + } + } + } + } + + /** + * This class is to be used for the Tuberculosis IGRA greater than 10 checkboxes value change listeners. + * It will clear the associated input field if the checkbox is checked and the + * value is less than or equal to 10. + * In reverse if the value is greater than 10 and the checkbox is not checked it will clear the input field. + *

+ * Note: ideally a custom component should be used for both fields, to avoid potential race conditions between the two listeners. + */ + protected static class TuberculosisIGRAGT10InputValueChangeListener implements ValueChangeListener { + + private final String igraInputFieldId; + private final String igraGT10FieldId; + private final BeanFieldGroup fieldGroup; + + public TuberculosisIGRAGT10InputValueChangeListener(BeanFieldGroup fg, String igraGT10FieldId, String igraInputFieldId) { + this.igraInputFieldId = igraInputFieldId; + this.igraGT10FieldId = igraGT10FieldId; + this.fieldGroup = fg; + } @Override public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { - // TODO Auto-generated method stub + final BeanItem beanItemDataSource = fieldGroup.getItemDataSource(); + + final Property igraValueProp = beanItemDataSource.getItemProperty(igraInputFieldId); + if (igraValueProp == null || !Number.class.isAssignableFrom(igraValueProp.getType())) { + return; + } + + // lets make sure the GT10 property is a boolean + final Property igraGT10Prop = beanItemDataSource.getItemProperty(igraGT10FieldId); + if (igraGT10Prop == null || !Boolean.class.isAssignableFrom(igraGT10Prop.getType())) { + // if we can't find the property, or we can't set it we don't care + return; + } + + // let's try to get the numeric input field and converted value + final Field igraInputField = fieldGroup.getField(igraInputFieldId); + if (igraInputField == null) { + return; + } + + @SuppressWarnings({ + "unchecked", + "rawtypes" }) + final Number igraNewValue = igraInputField.getValue() == null + ? null + : (Number) ConverterUtil.getConverter(igraInputField.getType(), (Class) igraValueProp.getType(), null /* current session */) + .convertToModel(igraInputField.getValue(), igraValueProp.getType(), null /* current locale */); + + // now let's try to determine if the checkbox is checked (we know it's a boolean) + @SuppressWarnings("unchecked") + final Field igraGT10Field = (Field) fieldGroup.getField(igraGT10FieldId); + if (igraGT10Field == null) { + // if we can't find the field, we don't care + return; + } + + // booleans come in two flavors: collection based and primitive + final boolean isCollection = Collection.class.isAssignableFrom(igraGT10Field.getType()); + + Boolean checked = false; + + // value can be true or false/null(presumed false) + if (!isCollection) { + // primitive booleans are easy + checked = igraGT10Field.getValue() == null ? null : Boolean.TRUE.equals(igraGT10Field.getValue()); + } else { + Collection set = (Collection) igraGT10Field.getValue(); + checked = set == null || set.isEmpty() ? null : set.contains(Boolean.TRUE); + } + + if (checked == null) { // the checbox is neither checked nor unchecked + checked = igraNewValue != null && igraNewValue.floatValue() > 10; + + if (!isCollection) { + // primitive booleans are easy + igraGT10Field.setValue(checked); + } else { + final HashSet set = new HashSet<>(); + set.add(checked); + igraGT10Field.setValue(set); + } + + // don't need to clear anything else because there was no check/uncheck before + return; + } + + if ((checked && igraNewValue != null && igraNewValue.floatValue() <= 10) // checked but value is filled in and less than 10 + || (!checked && igraNewValue != null && igraNewValue.floatValue() > 10) // not checked but value is filled in an greater than 10 + ) { + try { + igraInputField.clear(); + } catch (ReadOnlyException ex) { + // ignore read-only + } + } } } From fa77747a1fa53ba2f9cf69412527abeac7d34f98 Mon Sep 17 00:00:00 2001 From: Raul Bob Date: Tue, 17 Mar 2026 01:50:11 +0100 Subject: [PATCH 2/3] Added guards against number conversion errors --- .../sormas/ui/samples/PathogenTestForm.java | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java index 17ea1228c63..b2aa0ee30fa 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java @@ -40,11 +40,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.vaadin.server.UserError; +import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Label; import com.vaadin.v7.data.Property; import com.vaadin.v7.data.fieldgroup.BeanFieldGroup; import com.vaadin.v7.data.util.BeanItem; import com.vaadin.v7.data.util.converter.Converter; +import com.vaadin.v7.data.util.converter.Converter.ConversionException; import com.vaadin.v7.data.util.converter.ConverterUtil; import com.vaadin.v7.ui.AbstractSelect.ItemCaptionMode; import com.vaadin.v7.ui.CheckBox; @@ -64,6 +67,7 @@ import de.symeda.sormas.api.environment.environmentsample.Pathogen; import de.symeda.sormas.api.i18n.Captions; import de.symeda.sormas.api.i18n.I18nProperties; +import de.symeda.sormas.api.i18n.Strings; import de.symeda.sormas.api.i18n.Validations; import de.symeda.sormas.api.infrastructure.facility.FacilityDto; import de.symeda.sormas.api.infrastructure.facility.FacilityReferenceDto; @@ -1007,6 +1011,9 @@ public TuberculosisIGRAInputValueChangeListener(BeanFieldGroup this.fieldGroup = fg; } + @SuppressWarnings({ + "unchecked", + "rawtypes" }) @Override public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { @@ -1016,6 +1023,10 @@ public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { return; } + if (igraInputField instanceof AbstractComponent) { + ((AbstractComponent) igraInputField).setComponentError(null); + } + final BeanItem beanItemDataSource = fieldGroup.getItemDataSource(); // the input field is always a TextField with a String as value @@ -1035,13 +1046,21 @@ public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { // we need to convert the value to number // and we need to do it locale aware and need to finagle with types - @SuppressWarnings({ - "unchecked", - "rawtypes" }) - final Number igraNewValue = igraInputField.getValue() == null - ? null - : (Number) ConverterUtil.getConverter(igraInputField.getType(), (Class) igraValueProp.getType(), null /* current session */) - .convertToModel(igraInputField.getValue(), igraValueProp.getType(), null /* current locale */); + + Number igraNewValue = null; + + try { + igraNewValue = igraInputField.getValue() == null + ? null + : (Number) ConverterUtil + .getConverter(igraInputField.getType(), (Class) igraValueProp.getType(), null /* current session */) + .convertToModel(igraInputField.getValue(), igraValueProp.getType(), igraInputField.getLocale()); + } catch (ConversionException e) { + if (igraInputField instanceof AbstractComponent) { + ((AbstractComponent) igraInputField).setComponentError(new UserError(I18nProperties.getString(Strings.errorInvalidValue))); + } + return; + } final Boolean checked = igraNewValue == null ? null : igraNewValue.floatValue() > 10; @@ -1067,17 +1086,17 @@ public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { if (!isCollection) { // primitive booleans are easy final boolean currentChecked = Boolean.TRUE.equals(igraGT10Field.getValue()); - if (checked != null && checked != currentChecked) { + if (checked != null && checked.booleanValue() != currentChecked) { igraGT10Field.setValue(checked); } } else { // well have to do it the hard way final Collection currentSet = (Collection) igraGT10Field.getValue(); final boolean currentChecked = currentSet != null && !currentSet.isEmpty() && currentSet.contains(Boolean.TRUE); - if (checked != null && checked != currentChecked) { + if (checked != null && checked.booleanValue() != currentChecked) { final HashSet set = new HashSet<>(); set.add(checked); - igraGT10Field.setValue(set); + igraGT10Field.setValue(Collections.unmodifiableSet(set)); } } } @@ -1103,8 +1122,22 @@ public TuberculosisIGRAGT10InputValueChangeListener(BeanFieldGroup igraInputField = fieldGroup.getField(igraInputFieldId); + if (igraInputField == null) { + return; + } + + if (igraInputField instanceof AbstractComponent) { + ((AbstractComponent) igraInputField).setComponentError(null); + } + final BeanItem beanItemDataSource = fieldGroup.getItemDataSource(); final Property igraValueProp = beanItemDataSource.getItemProperty(igraInputFieldId); @@ -1119,20 +1152,21 @@ public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { return; } - // let's try to get the numeric input field and converted value - final Field igraInputField = fieldGroup.getField(igraInputFieldId); - if (igraInputField == null) { + Number igraNewValue = null; + + try { + igraNewValue = igraInputField.getValue() == null + ? null + : (Number) ConverterUtil + .getConverter(igraInputField.getType(), (Class) igraValueProp.getType(), null /* current session */) + .convertToModel(igraInputField.getValue(), igraValueProp.getType(), igraInputField.getLocale() /* current locale */); + } catch (ConversionException e) { + if (igraInputField instanceof AbstractComponent) { + ((AbstractComponent) igraInputField).setComponentError(new UserError(I18nProperties.getString(Strings.errorInvalidValue))); + } return; } - @SuppressWarnings({ - "unchecked", - "rawtypes" }) - final Number igraNewValue = igraInputField.getValue() == null - ? null - : (Number) ConverterUtil.getConverter(igraInputField.getType(), (Class) igraValueProp.getType(), null /* current session */) - .convertToModel(igraInputField.getValue(), igraValueProp.getType(), null /* current locale */); - // now let's try to determine if the checkbox is checked (we know it's a boolean) @SuppressWarnings("unchecked") final Field igraGT10Field = (Field) fieldGroup.getField(igraGT10FieldId); @@ -1164,7 +1198,7 @@ public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { } else { final HashSet set = new HashSet<>(); set.add(checked); - igraGT10Field.setValue(set); + igraGT10Field.setValue(Collections.unmodifiableSet(set)); } // don't need to clear anything else because there was no check/uncheck before From b34f40c0c6e5da2d31b0a33d601fe9b0ba60820e Mon Sep 17 00:00:00 2001 From: Raul Bob Date: Tue, 17 Mar 2026 09:19:26 +0100 Subject: [PATCH 3/3] Removed full type reference --- .../java/de/symeda/sormas/ui/samples/PathogenTestForm.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java index b2aa0ee30fa..d7d35120049 100644 --- a/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java +++ b/sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java @@ -1015,7 +1015,7 @@ public TuberculosisIGRAInputValueChangeListener(BeanFieldGroup "unchecked", "rawtypes" }) @Override - public void valueChange(com.vaadin.v7.data.Property.ValueChangeEvent event) { + public void valueChange(Property.ValueChangeEvent event) { final Field igraInputField = fieldGroup.getField(igraInputFieldId); @@ -1126,7 +1126,7 @@ public TuberculosisIGRAGT10InputValueChangeListener(BeanFieldGroup igraInputField = fieldGroup.getField(igraInputFieldId);