Fix change detection for textual things (#4076)

* Don't update unchanged things in .things file

There were two problems:
- The old things weren't removed, resulting in accumulation of duplicate things and comparing the new one against the old one resulting in erroneous update
-  Numeric values (usually entered as integer) in a newly loaded Channel Configuration properties are stored as BigDecimal with Scale 0, but subsequent normalization changed it to scale 1. This made equals() return false when it shouldn't. This leads to calling notifyListenersAboutUpdatedElement unnecessarily.

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
This commit is contained in:
jimtng 2024-05-02 05:41:53 -04:00 committed by GitHub
parent 21186d6168
commit eb2339907f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 57 additions and 15 deletions

View File

@ -177,10 +177,12 @@ public class ConfigUtil {
if (configDescriptionParameter != null) { if (configDescriptionParameter != null) {
Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter); Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter);
return normalizer.normalize(value); return normalizer.normalize(value);
} else if (value instanceof Boolean || value instanceof String || value instanceof BigDecimal) { } else if (value instanceof Boolean) {
return value; return NormalizerFactory.getNormalizer(Type.BOOLEAN).normalize(value);
} else if (value instanceof String) {
return NormalizerFactory.getNormalizer(Type.TEXT).normalize(value);
} else if (value instanceof Number) { } else if (value instanceof Number) {
return new BigDecimal(value.toString()); return NormalizerFactory.getNormalizer(Type.DECIMAL).normalize(value);
} else if (value instanceof Collection collection) { } else if (value instanceof Collection collection) {
return normalizeCollection(collection); return normalizeCollection(collection);
} }

View File

@ -35,13 +35,16 @@ final class DecimalNormalizer extends AbstractNormalizer {
return stripTrailingZeros(new BigDecimal(stringValue)); return stripTrailingZeros(new BigDecimal(stringValue));
} }
if (value instanceof Byte byteValue) { if (value instanceof Byte byteValue) {
return new BigDecimal(byteValue).setScale(1); return new BigDecimal(byteValue);
}
if (value instanceof Short shortValue) {
return new BigDecimal(shortValue);
} }
if (value instanceof Integer integerValue) { if (value instanceof Integer integerValue) {
return new BigDecimal(integerValue).setScale(1); return new BigDecimal(integerValue);
} }
if (value instanceof Long longValue) { if (value instanceof Long longValue) {
return new BigDecimal(longValue).setScale(1); return new BigDecimal(longValue);
} }
if (value instanceof Float floatValue) { if (value instanceof Float floatValue) {
return new BigDecimal(floatValue.toString()); return new BigDecimal(floatValue.toString());
@ -58,10 +61,13 @@ final class DecimalNormalizer extends AbstractNormalizer {
} }
private BigDecimal stripTrailingZeros(BigDecimal value) { private BigDecimal stripTrailingZeros(BigDecimal value) {
BigDecimal ret = new BigDecimal(value.stripTrailingZeros().toPlainString()); BigDecimal ret = value;
if (ret.scale() > 1) {
ret = ret.stripTrailingZeros();
if (ret.scale() == 0) { if (ret.scale() == 0) {
ret = ret.setScale(1); ret = ret.setScale(1);
} }
}
return ret; return ret;
} }
} }

View File

@ -51,4 +51,14 @@ public final class NormalizerFactory {
Normalizer ret = NORMALIZERS.get(configDescriptionParameter.getType()); Normalizer ret = NORMALIZERS.get(configDescriptionParameter.getType());
return configDescriptionParameter.isMultiple() ? new ListNormalizer(ret) : ret; return configDescriptionParameter.isMultiple() ? new ListNormalizer(ret) : ret;
} }
/**
* Returns the {@link Normalizer} for the given ConfigDescriptionParameter type.
*
* @param type the type
* @return the corresponding {@link Normalizer} (not null)
*/
public static Normalizer getNormalizer(Type type) {
return NORMALIZERS.get(type);
}
} }

View File

@ -160,18 +160,42 @@ public class ConfigurationTest {
@Test @Test
public void assertNormalizationInSetProperties() { public void assertNormalizationInSetProperties() {
Map<String, Object> properties = new HashMap<>(); Map<String, Object> properties = new HashMap<>();
properties.put("byteField", Byte.valueOf("1"));
properties.put("shortField", Short.valueOf("1"));
properties.put("intField", 1); properties.put("intField", 1);
properties.put("longField", Long.valueOf("1"));
properties.put("doubleField", Double.valueOf("1"));
properties.put("floatField", Float.valueOf("1"));
properties.put("bigDecimalField", BigDecimal.ONE);
Configuration configuration = new Configuration(); Configuration configuration = new Configuration();
configuration.setProperties(properties); configuration.setProperties(properties);
assertThat(configuration.get("byteField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("shortField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("intField"), is(equalTo(BigDecimal.ONE))); assertThat(configuration.get("intField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("longField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("doubleField"), is(equalTo(new BigDecimal("1.0"))));
assertThat(configuration.get("floatField"), is(equalTo(new BigDecimal("1.0"))));
assertThat(configuration.get("bigDecimalField"), is(equalTo(BigDecimal.ONE)));
} }
@Test @Test
public void assertNormalizationInPut() { public void assertNormalizationInPut() {
Configuration configuration = new Configuration(); Configuration configuration = new Configuration();
configuration.put("byteField", Byte.valueOf("1"));
configuration.put("shortField", Short.valueOf("1"));
configuration.put("intField", 1); configuration.put("intField", 1);
configuration.put("longField", Long.valueOf("1"));
configuration.put("doubleField", Double.valueOf("1"));
configuration.put("floatField", Float.valueOf("1"));
configuration.put("bigDecimalField", BigDecimal.ONE);
assertThat(configuration.get("byteField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("shortField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("intField"), is(equalTo(BigDecimal.ONE))); assertThat(configuration.get("intField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("longField"), is(equalTo(BigDecimal.ONE)));
assertThat(configuration.get("doubleField"), is(equalTo(new BigDecimal("1.0"))));
assertThat(configuration.get("floatField"), is(equalTo(new BigDecimal("1.0"))));
assertThat(configuration.get("bigDecimalField"), is(equalTo(BigDecimal.ONE)));
} }
@Test @Test

View File

@ -99,18 +99,19 @@ public class NormalizerTest {
ConfigDescriptionParameterBuilder.create("test", ConfigDescriptionParameter.Type.DECIMAL).build()); ConfigDescriptionParameterBuilder.create("test", ConfigDescriptionParameter.Type.DECIMAL).build());
assertThat(normalizer.normalize(null), is(nullValue())); assertThat(normalizer.normalize(null), is(nullValue()));
assertThat(normalizer.normalize(42), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize(42), is(equalTo(new BigDecimal("42"))));
assertThat(normalizer.normalize(42L), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize(42L), is(equalTo(new BigDecimal("42"))));
assertThat(normalizer.normalize((byte) 42), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize((byte) 42), is(equalTo(new BigDecimal("42"))));
assertThat(normalizer.normalize(42.0), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize(42.0), is(equalTo(new BigDecimal("42.0"))));
assertThat(normalizer.normalize(42.0f), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize(42.0f), is(equalTo(new BigDecimal("42.0"))));
assertThat(normalizer.normalize(42.0d), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize(42.0d), is(equalTo(new BigDecimal("42.0"))));
assertThat(normalizer.normalize(42.1), is(equalTo(new BigDecimal("42.1")))); assertThat(normalizer.normalize(42.1), is(equalTo(new BigDecimal("42.1"))));
assertThat(normalizer.normalize(42.88f), is(equalTo(new BigDecimal("42.88")))); assertThat(normalizer.normalize(42.88f), is(equalTo(new BigDecimal("42.88"))));
assertThat(normalizer.normalize(42.88d), is(equalTo(new BigDecimal("42.88")))); assertThat(normalizer.normalize(42.88d), is(equalTo(new BigDecimal("42.88"))));
assertThat(normalizer.normalize("42"), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize("42"), is(equalTo(new BigDecimal("42"))));
assertThat(normalizer.normalize("42.0"), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize("42.0"), is(equalTo(new BigDecimal("42.0"))));
assertThat(normalizer.normalize("42.1"), is(equalTo(new BigDecimal("42.1")))); assertThat(normalizer.normalize("42.1"), is(equalTo(new BigDecimal("42.1"))));
assertThat(normalizer.normalize("42.10"), is(equalTo(new BigDecimal("42.1"))));
assertThat(normalizer.normalize("42.11"), is(equalTo(new BigDecimal("42.11")))); assertThat(normalizer.normalize("42.11"), is(equalTo(new BigDecimal("42.11"))));
assertThat(normalizer.normalize("42.00"), is(equalTo(new BigDecimal("42.0")))); assertThat(normalizer.normalize("42.00"), is(equalTo(new BigDecimal("42.0"))));

View File

@ -605,8 +605,8 @@ class GenericThingProvider extends AbstractProviderLazyNullness<Thing> implement
if (!loadedXmlThingTypes.contains(factory.bundleName) || modelRepository == null) { if (!loadedXmlThingTypes.contains(factory.bundleName) || modelRepository == null) {
return return
} }
val oldThings = thingsMap.get(modelName).clone
val newThings = newArrayList() val newThings = newArrayList()
val oldThings = thingsMap.put(modelName, newThings)
val model = modelRepository.getModel(modelName) as ThingModel val model = modelRepository.getModel(modelName) as ThingModel
if (model !== null) { if (model !== null) {
@ -616,7 +616,6 @@ class GenericThingProvider extends AbstractProviderLazyNullness<Thing> implement
} }
newThings.forEach [ newThing | newThings.forEach [ newThing |
thingsMap.get(modelName).add(newThing)
val oldThing = oldThings.findFirst[it.UID == newThing.UID] val oldThing = oldThings.findFirst[it.UID == newThing.UID]
if (oldThing !== null) { if (oldThing !== null) {
if (!ThingHelper.equals(oldThing, newThing)) { if (!ThingHelper.equals(oldThing, newThing)) {