Adding null annotations to config.core.internal.normalization (#4505)

* Adding null annotations to config.core.internal.normalization

Signed-off-by: gael@lhopital.org <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital
2025-02-15 16:36:26 +01:00
committed by GitHub
parent f66720a30e
commit 8e597bde76
9 changed files with 107 additions and 128 deletions
@@ -177,20 +177,24 @@ public class ConfigUtil {
* @throws IllegalArgumentException if an invalid type has been given * @throws IllegalArgumentException if an invalid type has been given
*/ */
public static Object normalizeType(Object value, @Nullable ConfigDescriptionParameter configDescriptionParameter) { public static Object normalizeType(Object value, @Nullable ConfigDescriptionParameter configDescriptionParameter) {
Object result = null;
if (configDescriptionParameter != null) { if (configDescriptionParameter != null) {
Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter); Normalizer normalizer = NormalizerFactory.getNormalizer(configDescriptionParameter);
return normalizer.normalize(value); result = normalizer.normalize(value);
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
return NormalizerFactory.getNormalizer(Type.BOOLEAN).normalize(value); result = NormalizerFactory.getNormalizer(Type.BOOLEAN).normalize(value);
} else if (value instanceof String) { } else if (value instanceof String) {
return NormalizerFactory.getNormalizer(Type.TEXT).normalize(value); result = NormalizerFactory.getNormalizer(Type.TEXT).normalize(value);
} else if (value instanceof Number) { } 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) { } else if (value instanceof Collection collection) {
return normalizeCollection(collection); result = normalizeCollection(collection);
}
if (result != null) {
return result;
} }
throw new IllegalArgumentException( 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 * @param value the value to return as normalized type
* @return corresponding value as a valid 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); return normalizeType(value, null);
} }
@@ -12,6 +12,8 @@
*/ */
package org.openhab.core.config.core.internal.normalization; 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.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -21,12 +23,13 @@ import org.slf4j.LoggerFactory;
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
* @author Thomas Höfer - renamed normalizer interface and added javadoc * @author Thomas Höfer - renamed normalizer interface and added javadoc
*/ */
@NonNullByDefault
abstract class AbstractNormalizer implements Normalizer { abstract class AbstractNormalizer implements Normalizer {
protected final Logger logger = LoggerFactory.getLogger(AbstractNormalizer.class); protected final Logger logger = LoggerFactory.getLogger(AbstractNormalizer.class);
@Override @Override
public final Object normalize(Object value) { public final @Nullable Object normalize(@Nullable Object value) {
if (value == null) { if (value == null) {
return null; return null;
} }
@@ -12,6 +12,9 @@
*/ */
package org.openhab.core.config.core.internal.normalization; 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; import org.openhab.core.config.core.ConfigDescriptionParameter;
/** /**
@@ -24,32 +27,29 @@ import org.openhab.core.config.core.ConfigDescriptionParameter;
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
* @author Thomas Höfer - made class final and minor javadoc changes * @author Thomas Höfer - made class final and minor javadoc changes
*/ */
@NonNullByDefault
final class BooleanNormalizer extends AbstractNormalizer { final class BooleanNormalizer extends AbstractNormalizer {
private static final Set<String> TRUES = Set.of("true", "yes", "on", "1");
private static final Set<String> FALSES = Set.of("false", "no", "off", "0");
@Override @Override
public Object doNormalize(Object value) { public Object doNormalize(Object value) {
if (value instanceof Boolean) { return switch (value) {
return value; case Boolean bool -> bool;
} case Byte byteValue -> handleNumeric(byteValue.longValue());
if (value instanceof Byte byteValue) { case Integer integerValue -> handleNumeric(integerValue.longValue());
return handleNumeric(byteValue.longValue()); case Long longValue -> handleNumeric(longValue);
} default -> {
if (value instanceof Integer integerValue) { String s = value.toString().toLowerCase();
return handleNumeric(integerValue.longValue()); if (TRUES.contains(s)) {
} yield true;
if (value instanceof Long longValue) { } else if (FALSES.contains(s)) {
return handleNumeric(longValue); yield false;
} }
String s = value.toString(); logger.trace("Class \"{}\" cannot be converted to boolean.", value.getClass().getName());
if ("true".equalsIgnoreCase(s) || "yes".equalsIgnoreCase(s) || "on".equalsIgnoreCase(s) yield value;
|| "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;
} }
private Object handleNumeric(long numeric) { private Object handleNumeric(long numeric) {
@@ -57,9 +57,8 @@ final class BooleanNormalizer extends AbstractNormalizer {
return true; return true;
} else if (numeric == 0) { } else if (numeric == 0) {
return false; 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;
} }
} }
@@ -14,6 +14,7 @@ package org.openhab.core.config.core.internal.normalization;
import java.math.BigDecimal; import java.math.BigDecimal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.config.core.ConfigDescriptionParameter; import org.openhab.core.config.core.ConfigDescriptionParameter;
/** /**
@@ -23,41 +24,30 @@ import org.openhab.core.config.core.ConfigDescriptionParameter;
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
* @author Thomas Höfer - made class final and minor javadoc changes * @author Thomas Höfer - made class final and minor javadoc changes
*/ */
@NonNullByDefault
final class DecimalNormalizer extends AbstractNormalizer { final class DecimalNormalizer extends AbstractNormalizer {
@Override @Override
public Object doNormalize(Object value) { public Object doNormalize(Object value) {
try { try {
if (value instanceof BigDecimal bigDecimalValue) { return switch (value) {
return stripTrailingZeros(bigDecimalValue); case BigDecimal bigDecimalValue -> stripTrailingZeros(bigDecimalValue);
} case String stringValue -> stripTrailingZeros(new BigDecimal(stringValue));
if (value instanceof String stringValue) { case Byte byteValue -> new BigDecimal(byteValue);
return stripTrailingZeros(new BigDecimal(stringValue)); case Short shortValue -> new BigDecimal(shortValue);
} case Integer integerValue -> new BigDecimal(integerValue);
if (value instanceof Byte byteValue) { case Long longValue -> new BigDecimal(longValue);
return new BigDecimal(byteValue); case Float floatValue -> new BigDecimal(floatValue.toString());
} case Double doubleValue -> BigDecimal.valueOf(doubleValue);
if (value instanceof Short shortValue) { default -> {
return new BigDecimal(shortValue); logger.trace("Class \"{}\" cannot be converted to a decimal number.", value.getClass().getName());
} yield value;
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);
}
} catch (ArithmeticException | NumberFormatException e) { } catch (ArithmeticException | NumberFormatException e) {
logger.trace("\"{}\" is not a valid decimal number.", value, e); logger.trace("\"{}\" is not a valid decimal number.", value, e);
return value; return value;
} }
logger.trace("Class \"{}\" cannot be converted to a decimal number.", value.getClass().getName());
return value;
} }
private BigDecimal stripTrailingZeros(BigDecimal value) { private BigDecimal stripTrailingZeros(BigDecimal value) {
@@ -29,32 +29,22 @@ final class IntNormalizer extends AbstractNormalizer {
@Override @Override
public Object doNormalize(Object value) { public Object doNormalize(Object value) {
try { try {
if (value instanceof BigDecimal bigDecimalValue) { return switch (value) {
return bigDecimalValue.setScale(0, RoundingMode.UNNECESSARY); case BigDecimal bigDecimalValue -> bigDecimalValue.setScale(0, RoundingMode.UNNECESSARY);
} case Byte byteValue -> new BigDecimal(byteValue);
if (value instanceof Byte byteValue) { case Integer integerValue -> new BigDecimal(integerValue);
return new BigDecimal(byteValue); case Long longValue -> BigDecimal.valueOf(longValue);
} case String stringValue -> new BigDecimal(stringValue).setScale(0, RoundingMode.UNNECESSARY);
if (value instanceof Integer integerValue) { case Float floatValue -> new BigDecimal(floatValue.toString()).setScale(0, RoundingMode.UNNECESSARY);
return new BigDecimal(integerValue); case Double doubleValue -> BigDecimal.valueOf(doubleValue).setScale(0, RoundingMode.UNNECESSARY);
} default -> {
if (value instanceof Long longValue) { logger.trace("Class \"{}\" cannot be converted to an integer number.", value.getClass().getName());
return BigDecimal.valueOf(longValue); yield value;
} }
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);
}
} catch (ArithmeticException | NumberFormatException e) { } catch (ArithmeticException | NumberFormatException e) {
logger.trace("\"{}\" is not a valid integer number.", value, e); logger.trace("\"{}\" is not a valid integer number.", value, e);
return value; return value;
} }
logger.trace("Class \"{}\" cannot be converted to an integer number.", value.getClass().getName());
return value;
} }
} }
@@ -12,8 +12,12 @@
*/ */
package org.openhab.core.config.core.internal.normalization; package org.openhab.core.config.core.internal.normalization;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; 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 * 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 Simon Kaufmann - Initial contribution
* @author Thomas Höfer - made class final and minor javadoc changes * @author Thomas Höfer - made class final and minor javadoc changes
*/ */
@NonNullByDefault
final class ListNormalizer extends AbstractNormalizer { final class ListNormalizer extends AbstractNormalizer {
private final Normalizer delegate; private final Normalizer delegate;
@@ -30,43 +35,26 @@ final class ListNormalizer extends AbstractNormalizer {
this.delegate = delegate; this.delegate = delegate;
} }
@SuppressWarnings({ "rawtypes", "unchecked" }) @SuppressWarnings({ "unchecked" })
@Override @Override
public Object doNormalize(Object value) { public Object doNormalize(Object value) {
if (!isList(value)) { if (!isList(value)) {
List ret = new ArrayList(1); return Set.of(value).stream().map(delegate::normalize).toList();
ret.add(delegate.normalize(value)); } else if (isArray(value)) {
return ret; return Arrays.stream((Object[]) value).map(delegate::normalize).toList();
} } else if (value instanceof List list) {
if (isArray(value)) { return list.stream().map(delegate::normalize).toList();
List ret = new ArrayList(((Object[]) value).length); } else if (value instanceof Iterable iterable) {
for (Object object : ((Object[]) value)) { return StreamSupport.stream(iterable.spliterator(), false).map(delegate::normalize).toList();
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 value; return value;
} }
static boolean isList(Object value) { private static boolean isList(Object value) {
return isArray(value) || value instanceof Iterable; return isArray(value) || value instanceof Iterable;
} }
private static boolean isArray(Object object) { private static boolean isArray(Object object) {
return object != null && object.getClass().isArray(); return object.getClass().isArray();
} }
} }
@@ -12,6 +12,8 @@
*/ */
package org.openhab.core.config.core.internal.normalization; 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; import org.openhab.core.config.core.ConfigDescriptionParameter;
/** /**
@@ -22,6 +24,7 @@ import org.openhab.core.config.core.ConfigDescriptionParameter;
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
* @author Thomas Höfer - renamed from INormalizer and minor javadoc changes * @author Thomas Höfer - renamed from INormalizer and minor javadoc changes
*/ */
@NonNullByDefault
public interface Normalizer { public interface Normalizer {
/** /**
@@ -31,5 +34,6 @@ public interface Normalizer {
* @param value the object to be normalized * @param value the object to be normalized
* @return the well-defined type or the given object, if it was not possible to convert it * @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);
} }
@@ -12,10 +12,8 @@
*/ */
package org.openhab.core.config.core.internal.normalization; package org.openhab.core.config.core.internal.normalization;
import static java.util.Map.entry; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import java.util.Map;
import org.openhab.core.config.core.ConfigDescriptionParameter; import org.openhab.core.config.core.ConfigDescriptionParameter;
import org.openhab.core.config.core.ConfigDescriptionParameter.Type; 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 Simon Kaufmann - Initial contribution
* @author Thomas Höfer - introduced normalizers map and added precondition check as well as some additional javadoc * @author Thomas Höfer - introduced normalizers map and added precondition check as well as some additional javadoc
*/ */
@NonNullByDefault
public final class NormalizerFactory { public final class NormalizerFactory {
private static final Map<Type, Normalizer> NORMALIZERS = Map.ofEntries(entry(Type.BOOLEAN, new BooleanNormalizer()), private static final Normalizer BOOLEAN_NORMALIZER = new BooleanNormalizer();
entry(Type.TEXT, new TextNormalizer()), entry(Type.INTEGER, new IntNormalizer()), private static final Normalizer TEXT_NORMALIZER = new TextNormalizer();
entry(Type.DECIMAL, new DecimalNormalizer())); private static final Normalizer INT_NORMALIZER = new IntNormalizer();
private static final Normalizer DECIMAL_NORMALIZER = new DecimalNormalizer();
private NormalizerFactory() { private NormalizerFactory() {
// prevent instantiation // prevent instantiation
@@ -43,12 +43,12 @@ public final class NormalizerFactory {
* @return the corresponding {@link Normalizer} (not null) * @return the corresponding {@link Normalizer} (not null)
* @throws IllegalArgumentException if the given config description parameter is 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) { if (configDescriptionParameter == null) {
throw new IllegalArgumentException("The config description parameter must not be 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; return configDescriptionParameter.isMultiple() ? new ListNormalizer(ret) : ret;
} }
@@ -59,6 +59,11 @@ public final class NormalizerFactory {
* @return the corresponding {@link Normalizer} (not null) * @return the corresponding {@link Normalizer} (not null)
*/ */
public static Normalizer getNormalizer(Type type) { 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;
};
} }
} }
@@ -12,6 +12,7 @@
*/ */
package org.openhab.core.config.core.internal.normalization; package org.openhab.core.config.core.internal.normalization;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.config.core.ConfigDescriptionParameter; import org.openhab.core.config.core.ConfigDescriptionParameter;
/** /**
@@ -21,16 +22,11 @@ import org.openhab.core.config.core.ConfigDescriptionParameter;
* @author Simon Kaufmann - Initial contribution * @author Simon Kaufmann - Initial contribution
* @author Thomas Höfer - made class final and minor javadoc changes * @author Thomas Höfer - made class final and minor javadoc changes
*/ */
@NonNullByDefault
final class TextNormalizer extends AbstractNormalizer { final class TextNormalizer extends AbstractNormalizer {
@Override @Override
public Object doNormalize(Object value) { public Object doNormalize(Object value) {
if (value == null) { return value instanceof String ? value : value.toString();
return value;
}
if (value instanceof String) {
return value;
}
return value.toString();
} }
} }