]> git.basschouten.com Git - openhab-addons.git/commitdiff
[jpa] Fix restoring quantity types (#17215)
authorCody Cutrer <cody@cutrer.us>
Tue, 20 Aug 2024 13:27:52 +0000 (07:27 -0600)
committerGitHub <noreply@github.com>
Tue, 20 Aug 2024 13:27:52 +0000 (15:27 +0200)
* [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>
bundles/org.openhab.persistence.jpa/src/main/java/org/openhab/persistence/jpa/internal/JpaHistoricItem.java

index eaee4bb8caadb7f23c6288c592c3c925d5cf247b..ec7f7d8a12b4b4b2b8844c5790cb759f33806068 100644 (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) {