diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/ConfigUtil.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/ConfigUtil.java index f6645fcc0..74d87c5f0 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/ConfigUtil.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/ConfigUtil.java @@ -177,20 +177,24 @@ public class ConfigUtil { * @throws IllegalArgumentException if an invalid type has been given */ public static Object normalizeType(Object value, @Nullable ConfigDescriptionParameter configDescriptionParameter) { + Object result = null; if (configDescriptionParameter != null) { Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter); - return normalizer.normalize(value); + result = normalizer.normalize(value); } else if (value instanceof Boolean) { - return NormalizerFactory.getNormalizer(Type.BOOLEAN).normalize(value); + result = NormalizerFactory.getNormalizer(Type.BOOLEAN).normalize(value); } else if (value instanceof String) { - return NormalizerFactory.getNormalizer(Type.TEXT).normalize(value); + result = NormalizerFactory.getNormalizer(Type.TEXT).normalize(value); } else if (value instanceof Number) { - return NormalizerFactory.getNormalizer(Type.DECIMAL).normalize(value); + result = NormalizerFactory.getNormalizer(Type.DECIMAL).normalize(value); } else if (value instanceof Collection collection) { - return normalizeCollection(collection); + result = normalizeCollection(collection); + } + if (result != null) { + return result; } throw new IllegalArgumentException( - "Invalid type '{" + value.getClass().getCanonicalName() + "}' of configuration value!"); + "Invalid type '{%s}' of configuration value!".formatted(value.getClass().getCanonicalName())); } /** @@ -242,7 +246,7 @@ public class ConfigUtil { * @param value the value to return as normalized type * @return corresponding value as a valid type */ - public static Object normalizeType(Object value) { + public static @Nullable Object normalizeType(Object value) { return normalizeType(value, null); } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/AbstractNormalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/AbstractNormalizer.java index 5e9ab6468..5423c7ef0 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/AbstractNormalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/AbstractNormalizer.java @@ -12,6 +12,8 @@ */ package org.openhab.core.config.core.internal.normalization; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,12 +23,13 @@ import org.slf4j.LoggerFactory; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - renamed normalizer interface and added javadoc */ +@NonNullByDefault abstract class AbstractNormalizer implements Normalizer { protected final Logger logger = LoggerFactory.getLogger(AbstractNormalizer.class); @Override - public final Object normalize(Object value) { + public final @Nullable Object normalize(@Nullable Object value) { if (value == null) { return null; } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/BooleanNormalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/BooleanNormalizer.java index 7f2fe0cd8..8f37c9149 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/BooleanNormalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/BooleanNormalizer.java @@ -12,6 +12,9 @@ */ package org.openhab.core.config.core.internal.normalization; +import java.util.Set; + +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.config.core.ConfigDescriptionParameter; /** @@ -24,32 +27,29 @@ import org.openhab.core.config.core.ConfigDescriptionParameter; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - made class final and minor javadoc changes */ +@NonNullByDefault final class BooleanNormalizer extends AbstractNormalizer { + private static final Set TRUES = Set.of("true", "yes", "on", "1"); + private static final Set FALSES = Set.of("false", "no", "off", "0"); @Override public Object doNormalize(Object value) { - if (value instanceof Boolean) { - return value; - } - if (value instanceof Byte byteValue) { - return handleNumeric(byteValue.longValue()); - } - if (value instanceof Integer integerValue) { - return handleNumeric(integerValue.longValue()); - } - if (value instanceof Long longValue) { - return handleNumeric(longValue); - } - String s = value.toString(); - if ("true".equalsIgnoreCase(s) || "yes".equalsIgnoreCase(s) || "on".equalsIgnoreCase(s) - || "1".equalsIgnoreCase(s)) { - return true; - } else if ("false".equalsIgnoreCase(s) || "no".equalsIgnoreCase(s) || "off".equalsIgnoreCase(s) - || "0".equalsIgnoreCase(s)) { - return false; - } - logger.trace("Class \"{}\" cannot be converted to boolean.", value.getClass().getName()); - return value; + return switch (value) { + case Boolean bool -> bool; + case Byte byteValue -> handleNumeric(byteValue.longValue()); + case Integer integerValue -> handleNumeric(integerValue.longValue()); + case Long longValue -> handleNumeric(longValue); + default -> { + String s = value.toString().toLowerCase(); + if (TRUES.contains(s)) { + yield true; + } else if (FALSES.contains(s)) { + yield false; + } + logger.trace("Class \"{}\" cannot be converted to boolean.", value.getClass().getName()); + yield value; + } + }; } private Object handleNumeric(long numeric) { @@ -57,9 +57,8 @@ final class BooleanNormalizer extends AbstractNormalizer { return true; } else if (numeric == 0) { return false; - } else { - logger.trace("\"{}\" cannot be interpreted as a boolean.", numeric); - return numeric; } + logger.trace("\"{}\" cannot be interpreted as a boolean.", numeric); + return numeric; } } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/DecimalNormalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/DecimalNormalizer.java index 71e1ea5c2..1d8c081ef 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/DecimalNormalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/DecimalNormalizer.java @@ -14,6 +14,7 @@ package org.openhab.core.config.core.internal.normalization; import java.math.BigDecimal; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.config.core.ConfigDescriptionParameter; /** @@ -23,41 +24,30 @@ import org.openhab.core.config.core.ConfigDescriptionParameter; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - made class final and minor javadoc changes */ +@NonNullByDefault final class DecimalNormalizer extends AbstractNormalizer { @Override public Object doNormalize(Object value) { try { - if (value instanceof BigDecimal bigDecimalValue) { - return stripTrailingZeros(bigDecimalValue); - } - if (value instanceof String stringValue) { - return stripTrailingZeros(new BigDecimal(stringValue)); - } - if (value instanceof Byte byteValue) { - return new BigDecimal(byteValue); - } - if (value instanceof Short shortValue) { - return new BigDecimal(shortValue); - } - if (value instanceof Integer integerValue) { - return new BigDecimal(integerValue); - } - if (value instanceof Long longValue) { - return new BigDecimal(longValue); - } - if (value instanceof Float floatValue) { - return new BigDecimal(floatValue.toString()); - } - if (value instanceof Double doubleValue) { - return BigDecimal.valueOf(doubleValue); - } + return switch (value) { + case BigDecimal bigDecimalValue -> stripTrailingZeros(bigDecimalValue); + case String stringValue -> stripTrailingZeros(new BigDecimal(stringValue)); + case Byte byteValue -> new BigDecimal(byteValue); + case Short shortValue -> new BigDecimal(shortValue); + case Integer integerValue -> new BigDecimal(integerValue); + case Long longValue -> new BigDecimal(longValue); + case Float floatValue -> new BigDecimal(floatValue.toString()); + case Double doubleValue -> BigDecimal.valueOf(doubleValue); + default -> { + logger.trace("Class \"{}\" cannot be converted to a decimal number.", value.getClass().getName()); + yield value; + } + }; } catch (ArithmeticException | NumberFormatException e) { logger.trace("\"{}\" is not a valid decimal number.", value, e); return value; } - logger.trace("Class \"{}\" cannot be converted to a decimal number.", value.getClass().getName()); - return value; } private BigDecimal stripTrailingZeros(BigDecimal value) { diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/IntNormalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/IntNormalizer.java index e19cf9d4c..2a3680044 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/IntNormalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/IntNormalizer.java @@ -29,32 +29,22 @@ final class IntNormalizer extends AbstractNormalizer { @Override public Object doNormalize(Object value) { try { - if (value instanceof BigDecimal bigDecimalValue) { - return bigDecimalValue.setScale(0, RoundingMode.UNNECESSARY); - } - if (value instanceof Byte byteValue) { - return new BigDecimal(byteValue); - } - if (value instanceof Integer integerValue) { - return new BigDecimal(integerValue); - } - if (value instanceof Long longValue) { - return BigDecimal.valueOf(longValue); - } - if (value instanceof String stringValue) { - return new BigDecimal(stringValue).setScale(0, RoundingMode.UNNECESSARY); - } - if (value instanceof Float floatValue) { - return new BigDecimal(floatValue.toString()).setScale(0, RoundingMode.UNNECESSARY); - } - if (value instanceof Double doubleValue) { - return BigDecimal.valueOf(doubleValue).setScale(0, RoundingMode.UNNECESSARY); - } + return switch (value) { + case BigDecimal bigDecimalValue -> bigDecimalValue.setScale(0, RoundingMode.UNNECESSARY); + case Byte byteValue -> new BigDecimal(byteValue); + case Integer integerValue -> new BigDecimal(integerValue); + case Long longValue -> BigDecimal.valueOf(longValue); + case String stringValue -> new BigDecimal(stringValue).setScale(0, RoundingMode.UNNECESSARY); + case Float floatValue -> new BigDecimal(floatValue.toString()).setScale(0, RoundingMode.UNNECESSARY); + case Double doubleValue -> BigDecimal.valueOf(doubleValue).setScale(0, RoundingMode.UNNECESSARY); + default -> { + logger.trace("Class \"{}\" cannot be converted to an integer number.", value.getClass().getName()); + yield value; + } + }; } catch (ArithmeticException | NumberFormatException e) { logger.trace("\"{}\" is not a valid integer number.", value, e); return value; } - logger.trace("Class \"{}\" cannot be converted to an integer number.", value.getClass().getName()); - return value; } } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/ListNormalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/ListNormalizer.java index 3418c1f84..d3f6a2d7e 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/ListNormalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/ListNormalizer.java @@ -12,8 +12,12 @@ */ package org.openhab.core.config.core.internal.normalization; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Set; +import java.util.stream.StreamSupport; + +import org.eclipse.jdt.annotation.NonNullByDefault; /** * The normalizer for configuration parameters allowing multiple values. It converts all collections/arrays to a @@ -22,6 +26,7 @@ import java.util.List; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - made class final and minor javadoc changes */ +@NonNullByDefault final class ListNormalizer extends AbstractNormalizer { private final Normalizer delegate; @@ -30,43 +35,26 @@ final class ListNormalizer extends AbstractNormalizer { this.delegate = delegate; } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "unchecked" }) @Override public Object doNormalize(Object value) { if (!isList(value)) { - List ret = new ArrayList(1); - ret.add(delegate.normalize(value)); - return ret; - } - if (isArray(value)) { - List ret = new ArrayList(((Object[]) value).length); - for (Object object : ((Object[]) value)) { - ret.add(delegate.normalize(object)); - } - return ret; - } - if (value instanceof List list) { - List ret = new ArrayList(list.size()); - for (Object object : list) { - ret.add(delegate.normalize(object)); - } - return ret; - } - if (value instanceof Iterable iterable) { - List ret = new ArrayList(); - for (Object object : iterable) { - ret.add(delegate.normalize(object)); - } - return ret; + return Set.of(value).stream().map(delegate::normalize).toList(); + } else if (isArray(value)) { + return Arrays.stream((Object[]) value).map(delegate::normalize).toList(); + } else if (value instanceof List list) { + return list.stream().map(delegate::normalize).toList(); + } else if (value instanceof Iterable iterable) { + return StreamSupport.stream(iterable.spliterator(), false).map(delegate::normalize).toList(); } return value; } - static boolean isList(Object value) { + private static boolean isList(Object value) { return isArray(value) || value instanceof Iterable; } private static boolean isArray(Object object) { - return object != null && object.getClass().isArray(); + return object.getClass().isArray(); } } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/Normalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/Normalizer.java index 8bb2970ab..02249c286 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/Normalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/Normalizer.java @@ -12,6 +12,8 @@ */ package org.openhab.core.config.core.internal.normalization; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.config.core.ConfigDescriptionParameter; /** @@ -22,6 +24,7 @@ import org.openhab.core.config.core.ConfigDescriptionParameter; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - renamed from INormalizer and minor javadoc changes */ +@NonNullByDefault public interface Normalizer { /** @@ -31,5 +34,6 @@ public interface Normalizer { * @param value the object to be normalized * @return the well-defined type or the given object, if it was not possible to convert it */ - Object normalize(Object value); + @Nullable + Object normalize(@Nullable Object value); } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/NormalizerFactory.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/NormalizerFactory.java index 8c982d8ba..31c84386b 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/NormalizerFactory.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/NormalizerFactory.java @@ -12,10 +12,8 @@ */ package org.openhab.core.config.core.internal.normalization; -import static java.util.Map.entry; - -import java.util.Map; - +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.core.config.core.ConfigDescriptionParameter; import org.openhab.core.config.core.ConfigDescriptionParameter.Type; @@ -26,11 +24,13 @@ import org.openhab.core.config.core.ConfigDescriptionParameter.Type; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - introduced normalizers map and added precondition check as well as some additional javadoc */ +@NonNullByDefault public final class NormalizerFactory { - private static final Map NORMALIZERS = Map.ofEntries(entry(Type.BOOLEAN, new BooleanNormalizer()), - entry(Type.TEXT, new TextNormalizer()), entry(Type.INTEGER, new IntNormalizer()), - entry(Type.DECIMAL, new DecimalNormalizer())); + private static final Normalizer BOOLEAN_NORMALIZER = new BooleanNormalizer(); + private static final Normalizer TEXT_NORMALIZER = new TextNormalizer(); + private static final Normalizer INT_NORMALIZER = new IntNormalizer(); + private static final Normalizer DECIMAL_NORMALIZER = new DecimalNormalizer(); private NormalizerFactory() { // prevent instantiation @@ -43,12 +43,12 @@ public final class NormalizerFactory { * @return the corresponding {@link Normalizer} (not null) * @throws IllegalArgumentException if the given config description parameter is null */ - public static Normalizer getNormalizer(ConfigDescriptionParameter configDescriptionParameter) { + public static Normalizer getNormalizer(@Nullable ConfigDescriptionParameter configDescriptionParameter) { if (configDescriptionParameter == null) { throw new IllegalArgumentException("The config description parameter must not be null."); } - Normalizer ret = NORMALIZERS.get(configDescriptionParameter.getType()); + Normalizer ret = getNormalizer(configDescriptionParameter.getType()); return configDescriptionParameter.isMultiple() ? new ListNormalizer(ret) : ret; } @@ -59,6 +59,11 @@ public final class NormalizerFactory { * @return the corresponding {@link Normalizer} (not null) */ public static Normalizer getNormalizer(Type type) { - return NORMALIZERS.get(type); + return switch (type) { + case BOOLEAN -> BOOLEAN_NORMALIZER; + case DECIMAL -> DECIMAL_NORMALIZER; + case INTEGER -> INT_NORMALIZER; + case TEXT -> TEXT_NORMALIZER; + }; } } diff --git a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/TextNormalizer.java b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/TextNormalizer.java index 827077a43..849411444 100644 --- a/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/TextNormalizer.java +++ b/bundles/org.openhab.core.config.core/src/main/java/org/openhab/core/config/core/internal/normalization/TextNormalizer.java @@ -12,6 +12,7 @@ */ package org.openhab.core.config.core.internal.normalization; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.config.core.ConfigDescriptionParameter; /** @@ -21,16 +22,11 @@ import org.openhab.core.config.core.ConfigDescriptionParameter; * @author Simon Kaufmann - Initial contribution * @author Thomas Höfer - made class final and minor javadoc changes */ +@NonNullByDefault final class TextNormalizer extends AbstractNormalizer { @Override public Object doNormalize(Object value) { - if (value == null) { - return value; - } - if (value instanceof String) { - return value; - } - return value.toString(); + return value instanceof String ? value : value.toString(); } }