[jpa] Fix restoring quantity types (#17215)

* [jpa] Fix restoring quantity types

Double.parseDouble throws NumberFormatException if the persisted state
includes a unit. So parse it as a QuantityType, and then apply unit
conversions as necessary.

Signed-off-by: Cody Cutrer <cody@cutrer.us>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Cody Cutrer 2024-08-20 07:27:52 -06:00 committed by Ciprian Pascu
parent 64331da0ad
commit d528605bcf

View File

@ -17,11 +17,13 @@ import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.items.Item;
import org.openhab.core.library.items.ContactItem;
import org.openhab.core.library.items.DateTimeItem;
@ -39,10 +41,13 @@ import org.openhab.core.library.types.PointType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringListType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.library.unit.Units;
import org.openhab.core.persistence.HistoricItem;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.openhab.persistence.jpa.internal.model.JpaPersistentItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The historic item as returned when querying the service.
@ -52,6 +57,7 @@ import org.openhab.persistence.jpa.internal.model.JpaPersistentItem;
*/
@NonNullByDefault
public class JpaHistoricItem implements HistoricItem {
private static final Logger logger = LoggerFactory.getLogger(JpaHistoricItem.class);
private final String name;
private final State state;
@ -91,7 +97,8 @@ public class JpaHistoricItem implements HistoricItem {
* @return list of historic items
*/
public static List<HistoricItem> fromResultList(List<JpaPersistentItem> jpaQueryResult, Item item) {
return jpaQueryResult.stream().map(pItem -> fromPersistedItem(pItem, item)).collect(Collectors.toList());
return jpaQueryResult.stream().map(pItem -> fromPersistedItem(pItem, item)).filter(Objects::nonNull)
.map(Objects::requireNonNull).collect(Collectors.toList());
}
/**
@ -101,12 +108,26 @@ public class JpaHistoricItem implements HistoricItem {
* @param item the source reference Item
* @return historic item
*/
public static HistoricItem fromPersistedItem(JpaPersistentItem pItem, Item item) {
public static @Nullable HistoricItem fromPersistedItem(JpaPersistentItem pItem, Item item) {
State state;
if (item instanceof NumberItem numberItem) {
Unit<?> unit = numberItem.getUnit();
double value = Double.parseDouble(pItem.getValue());
state = (unit == null) ? new DecimalType(value) : new QuantityType<>(value, unit);
QuantityType<?> value = QuantityType.valueOf(pItem.getValue());
if (unit == null) {
// Item has no unit; drop any persisted unit
state = Objects.requireNonNull(value.as(DecimalType.class));
} else if (value.getUnit() == Units.ONE) {
// No persisted unit; assume the item's unit
state = new QuantityType<>(value.toBigDecimal(), unit);
} else {
// Ensure we return in the item's unit
state = value.toUnit(unit);
if (state == null) {
logger.warn("Persisted state {} for item {} is incompatible with item's unit {}; ignoring", value,
item.getName(), unit);
return null;
}
}
} else if (item instanceof DimmerItem) {
state = new PercentType(Integer.parseInt(pItem.getValue()));
} else if (item instanceof SwitchItem) {