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
*/
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);
}
@@ -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;
}
@@ -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<String> TRUES = Set.of("true", "yes", "on", "1");
private static final Set<String> 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;
}
}
@@ -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) {
@@ -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;
}
}
@@ -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();
}
}
@@ -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);
}
@@ -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<Type, Normalizer> 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;
};
}
}
@@ -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();
}
}