]> git.basschouten.com Git - openhab-addons.git/commitdiff
[gardena] Fix null annotation issue (and compiler warning) (#12957)
authorJacob Laursen <jacob-github@vindvejr.dk>
Thu, 23 Jun 2022 07:11:20 +0000 (09:11 +0200)
committerGitHub <noreply@github.com>
Thu, 23 Jun 2022 07:11:20 +0000 (09:11 +0200)
* Fix compiler warning
* Add basic test coverage for DataItem deserialization
* Add full prefixes to attributes variables
* Add missing newlines at end of test payload files
* Add full prefix to attributes variable

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
19 files changed:
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/GardenaSmartImpl.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/handler/GardenaThingHandler.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/Device.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/CommonServiceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/CreateWebSocketDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/CreateWebSocketRequest.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/DataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/DeviceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/LocationDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/MowerServiceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/PowerSocketServiceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/SensorServiceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/ValveServiceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/ValveSetServiceDataItem.java
bundles/org.openhab.binding.gardena/src/main/java/org/openhab/binding/gardena/internal/model/dto/api/WebSocketDataItem.java
bundles/org.openhab.binding.gardena/src/test/java/org/openhab/binding/gardena/DataItemTest.java [new file with mode: 0644]
bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/DeviceDataItem.json [new file with mode: 0644]
bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/SensorServiceDataItem.json [new file with mode: 0644]
bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/SensorServiceDataItemNoAttributes.json [new file with mode: 0644]

index fab20abefb946e900a937f944f71a00d5c44b694..f06d70fb4f7c41b9e6080ce050dacf366bdbbb32 100644 (file)
@@ -43,10 +43,12 @@ import org.openhab.binding.gardena.internal.model.DataItemDeserializer;
 import org.openhab.binding.gardena.internal.model.dto.Device;
 import org.openhab.binding.gardena.internal.model.dto.api.CreateWebSocketRequest;
 import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
+import org.openhab.binding.gardena.internal.model.dto.api.Location;
 import org.openhab.binding.gardena.internal.model.dto.api.LocationDataItem;
 import org.openhab.binding.gardena.internal.model.dto.api.LocationResponse;
 import org.openhab.binding.gardena.internal.model.dto.api.LocationsResponse;
 import org.openhab.binding.gardena.internal.model.dto.api.PostOAuth2Response;
+import org.openhab.binding.gardena.internal.model.dto.api.WebSocket;
 import org.openhab.binding.gardena.internal.model.dto.api.WebSocketCreatedResponse;
 import org.openhab.binding.gardena.internal.model.dto.command.GardenaCommand;
 import org.openhab.binding.gardena.internal.model.dto.command.GardenaCommandRequest;
@@ -153,9 +155,14 @@ public class GardenaSmartImpl implements GardenaSmart, GardenaSmartWebSocketList
     private void startWebsockets() throws Exception {
         for (LocationDataItem location : locationsResponse.data) {
             WebSocketCreatedResponse webSocketCreatedResponse = getWebsocketInfo(location.id);
-            String socketId = id + "-" + location.attributes.name;
+            Location locationAttributes = location.attributes;
+            WebSocket webSocketAttributes = webSocketCreatedResponse.data.attributes;
+            if (locationAttributes == null || webSocketAttributes == null) {
+                continue;
+            }
+            String socketId = id + "-" + locationAttributes.name;
             webSockets.put(location.id, new GardenaSmartWebSocket(this, webSocketClient, scheduler,
-                    webSocketCreatedResponse.data.attributes.url, token, socketId, location.id));
+                    webSocketAttributes.url, token, socketId, location.id));
         }
     }
 
@@ -391,7 +398,10 @@ public class GardenaSmartImpl implements GardenaSmart, GardenaSmartWebSocketList
             Thread.sleep(3000);
             WebSocketCreatedResponse webSocketCreatedResponse = getWebsocketInfo(socket.getLocationID());
             // only restart single socket, do not restart binding
-            socket.restart(webSocketCreatedResponse.data.attributes.url);
+            WebSocket webSocketAttributes = webSocketCreatedResponse.data.attributes;
+            if (webSocketAttributes != null) {
+                socket.restart(webSocketAttributes.url);
+            }
         } catch (Exception ex) {
             // restart binding on error
             logger.warn("Restarting GardenaSmart Webservice failed ({}): {}, restarting binding", socket.getSocketID(),
index 67df16068b8d75a7c7a804d3e7b29b59cb301816..b9661bcd5225200810281c01267cd151ded133a6 100644 (file)
@@ -27,6 +27,7 @@ import org.openhab.binding.gardena.internal.GardenaSmartEventListener;
 import org.openhab.binding.gardena.internal.exception.GardenaDeviceNotFoundException;
 import org.openhab.binding.gardena.internal.exception.GardenaException;
 import org.openhab.binding.gardena.internal.model.dto.Device;
+import org.openhab.binding.gardena.internal.model.dto.api.CommonService;
 import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
 import org.openhab.binding.gardena.internal.model.dto.command.GardenaCommand;
 import org.openhab.binding.gardena.internal.model.dto.command.MowerCommand;
@@ -284,7 +285,9 @@ public class GardenaThingHandler extends BaseThingHandler {
         ThingStatus newStatus = ThingStatus.ONLINE;
         ThingStatusDetail newDetail = ThingStatusDetail.NONE;
 
-        if (!CONNECTION_STATUS_ONLINE.equals(device.common.attributes.rfLinkState.value)) {
+        CommonService commonServiceAttributes = device.common.attributes;
+        if (commonServiceAttributes == null
+                || !CONNECTION_STATUS_ONLINE.equals(commonServiceAttributes.rfLinkState.value)) {
             newStatus = ThingStatus.OFFLINE;
             newDetail = ThingStatusDetail.COMMUNICATION_ERROR;
         }
index 6c6d091deefc436280163662b7119bb6f613e8c9..b9801ed6dafb38e658f29813727762cae9587b9a 100644 (file)
@@ -19,9 +19,11 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.openhab.binding.gardena.internal.exception.GardenaException;
+import org.openhab.binding.gardena.internal.model.dto.api.CommonService;
 import org.openhab.binding.gardena.internal.model.dto.api.CommonServiceDataItem;
 import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
 import org.openhab.binding.gardena.internal.model.dto.api.DeviceDataItem;
+import org.openhab.binding.gardena.internal.model.dto.api.Location;
 import org.openhab.binding.gardena.internal.model.dto.api.LocationDataItem;
 import org.openhab.binding.gardena.internal.model.dto.api.MowerServiceDataItem;
 import org.openhab.binding.gardena.internal.model.dto.api.PowerSocketServiceDataItem;
@@ -82,8 +84,10 @@ public class Device {
      */
     public void evaluateDeviceType() {
         if (deviceType == null) {
-            if (common.attributes.modelType.value.toLowerCase().startsWith(DEVICE_TYPE_PREFIX)) {
-                String modelType = common.attributes.modelType.value.toLowerCase();
+            CommonService commonServiceAttributes = common.attributes;
+            if (commonServiceAttributes != null
+                    && commonServiceAttributes.modelType.value.toLowerCase().startsWith(DEVICE_TYPE_PREFIX)) {
+                String modelType = commonServiceAttributes.modelType.value.toLowerCase();
                 modelType = modelType.substring(14);
                 deviceType = modelType.replace(" ", "_");
             } else {
@@ -111,8 +115,9 @@ public class Device {
             // ignore
         } else if (dataItem instanceof LocationDataItem) {
             LocationDataItem locationDataItem = (LocationDataItem) dataItem;
-            if (locationDataItem.attributes != null) {
-                location = locationDataItem.attributes.name;
+            Location locationAttributes = locationDataItem.attributes;
+            if (locationAttributes != null) {
+                location = locationAttributes.name;
             }
         } else if (dataItem instanceof CommonServiceDataItem) {
             common = (CommonServiceDataItem) dataItem;
index 850a67d75b77c4424119ca7cb11612811c11ac8e..04ffcbf201221ccb226ef38e766f6c847f26d593 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
 
-public class CommonServiceDataItem extends DataItem<CommonService> {
+public class CommonServiceDataItem extends DataItem<@NonNull CommonService> {
 }
index 47c61abb7885544bb29f39eb01397fe596cacf89..09cf91cd83fe93f98ea31d78b10d8aa8f750247b 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
 
-public class CreateWebSocketDataItem extends DataItem<CreateWebSocket> {
+public class CreateWebSocketDataItem extends DataItem<@NonNull CreateWebSocket> {
 }
index 873dfbf617dc0e1dc65feb16d5278805c4fb9a34..5c0e796252a32637349192da077a7040ea13e6de 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
 
+@NonNullByDefault
 public class CreateWebSocketRequest {
     public CreateWebSocketDataItem data;
 
index 5769e782aede7808f123c673dcd7f72bc22baa7a..8c6f7b974d521be497beb251f9d55a7d084578ac 100644 (file)
@@ -12,6 +12,8 @@
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.gardena.internal.util.StringUtils;
 
 /**
@@ -20,7 +22,7 @@ import org.openhab.binding.gardena.internal.util.StringUtils;
  * @author Gerhard Riegler - Initial contribution
  */
 
-public class DataItem<T> {
+public class DataItem<@NonNull T> {
     public String id;
     public String type;
 
@@ -28,5 +30,5 @@ public class DataItem<T> {
         return StringUtils.substringBeforeLast(id, ":");
     }
 
-    public T attributes;
+    public @Nullable T attributes;
 }
index 1b15da915f5623bcdf3740dea615a2df0139ac91..f81e7032c7b216e6d7b1aa56e411c3a098787296 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
 
-public class DeviceDataItem extends DataItem<Void> {
+public class DeviceDataItem extends DataItem<@NonNull Void> {
 }
index 0950fd9432d92818597a22adbf9211c985263b93..2cd1509903186d19f3669cb3bba75a07f4b11f90 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
 
-public class LocationDataItem extends DataItem<Location> {
+public class LocationDataItem extends DataItem<@NonNull Location> {
 }
index 705098382f5e76c30b4197772d7e222d2b5dfede..21973dd09a56dcf918efa37146714dc8b3ce98e2 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
 
-public class MowerServiceDataItem extends DataItem<MowerService> {
+public class MowerServiceDataItem extends DataItem<@NonNull MowerService> {
 }
index 86ef246b96e74e47daaacc3eb89b46008f2f49fe..d9890164107bec577cb6cdc98f7453b7cc502950 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
-public class PowerSocketServiceDataItem extends DataItem<PowerSocketService> {
+public class PowerSocketServiceDataItem extends DataItem<@NonNull PowerSocketService> {
 }
index f29ce8203ee8bde457004e51a6b5f10cb5c3cacc..dd9b49cbe6ae9054e961c94f5140f64c9b798be2 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
-public class SensorServiceDataItem extends DataItem<SensorService> {
+public class SensorServiceDataItem extends DataItem<@NonNull SensorService> {
 }
index 54f5061adcbba4203a840568ac2982d5cb336ae5..213e56fc20e477c95418f5dc393ec27941d22118 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
-public class ValveServiceDataItem extends DataItem<ValveService> {
+public class ValveServiceDataItem extends DataItem<@NonNull ValveService> {
 }
index 0c8974f1b0f4da99e0752b765954387f3fd05ce5..1d492e3e0588a52851a4de65057ea8d2242c228b 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
-public class ValveSetServiceDataItem extends DataItem<ValveSetService> {
+public class ValveSetServiceDataItem extends DataItem<@NonNull ValveSetService> {
 }
index 61964ea9dde17300b6b2bea5bcdbdcb9e57bc40a..fce96e39db9901f59c6fad5f35832deac2d63503 100644 (file)
  */
 package org.openhab.binding.gardena.internal.model.dto.api;
 
+import org.eclipse.jdt.annotation.NonNull;
+
 /**
  * Represents a Gardena object that is sent via the Gardena API.
  *
  * @author Gerhard Riegler - Initial contribution
  */
-public class WebSocketDataItem extends DataItem<WebSocket> {
+public class WebSocketDataItem extends DataItem<@NonNull WebSocket> {
 }
diff --git a/bundles/org.openhab.binding.gardena/src/test/java/org/openhab/binding/gardena/DataItemTest.java b/bundles/org.openhab.binding.gardena/src/test/java/org/openhab/binding/gardena/DataItemTest.java
new file mode 100644 (file)
index 0000000..ec3bb00
--- /dev/null
@@ -0,0 +1,85 @@
+/**
+ * Copyright (c) 2010-2022 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.gardena;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Objects;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.junit.jupiter.api.Test;
+import org.openhab.binding.gardena.internal.model.DataItemDeserializer;
+import org.openhab.binding.gardena.internal.model.dto.api.DataItem;
+import org.openhab.binding.gardena.internal.model.dto.api.DeviceDataItem;
+import org.openhab.binding.gardena.internal.model.dto.api.SensorService;
+import org.openhab.binding.gardena.internal.model.dto.api.SensorServiceDataItem;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * Tests for {@link DataItem} deserialization.
+ *
+ * @author Jacob Laursen - Initial contribution
+ */
+@NonNullByDefault
+public class DataItemTest {
+
+    private Gson gson = new GsonBuilder().registerTypeAdapter(DataItem.class, new DataItemDeserializer()).create();
+
+    public <T> T getObjectFromJson(String filename, Class<T> clazz) throws IOException {
+        try (InputStream inputStream = DataItemTest.class.getResourceAsStream(filename)) {
+            if (inputStream == null) {
+                throw new IOException("inputstream is null");
+            }
+            byte[] bytes = inputStream.readAllBytes();
+            if (bytes == null) {
+                throw new IOException("Resulting byte-array empty");
+            }
+            String json = new String(bytes, StandardCharsets.UTF_8);
+            return Objects.requireNonNull(gson.fromJson(json, clazz));
+        }
+    }
+
+    @Test
+    public void sensorServiceWellformed() throws IOException {
+        DataItem<?> dataItem = getObjectFromJson("SensorServiceDataItem.json", DataItem.class);
+        assertInstanceOf(SensorServiceDataItem.class, dataItem);
+        assertEquals("SENSOR", dataItem.type);
+        SensorService attributes = ((SensorServiceDataItem) dataItem).attributes;
+        assertNotNull(attributes);
+        assertEquals(55, attributes.soilHumidity.value);
+    }
+
+    @Test
+    public void sensorServiceNoAttributes() throws IOException {
+        DataItem<?> dataItem = getObjectFromJson("SensorServiceDataItemNoAttributes.json", DataItem.class);
+        assertInstanceOf(SensorServiceDataItem.class, dataItem);
+        assertEquals("SENSOR", dataItem.type);
+        assertNull((SensorServiceDataItem) dataItem.attributes);
+    }
+
+    @Test
+    public void device() throws IOException {
+        DataItem<?> dataItem = getObjectFromJson("DeviceDataItem.json", DataItem.class);
+        assertInstanceOf(DeviceDataItem.class, dataItem);
+        assertEquals("DEVICE", dataItem.type);
+        assertNull((SensorServiceDataItem) dataItem.attributes);
+    }
+}
diff --git a/bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/DeviceDataItem.json b/bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/DeviceDataItem.json
new file mode 100644 (file)
index 0000000..9b9ed0e
--- /dev/null
@@ -0,0 +1,24 @@
+{
+       "id": "0162efc2-0b62-4983-aa1d-d72442008b7c",
+       "type": "DEVICE",
+       "relationships": {
+               "location": {
+                       "data": {
+                               "id": "d01b4d00-945a-4639-bf5a-f73d2030dfe0",
+                               "type": "LOCATION"
+                       }
+               },
+               "services": {
+                       "data": [
+                               {
+                                       "id": "0162efc2-0b62-4983-aa1d-d72442008b7c",
+                                       "type": "SENSOR"
+                               },
+                               {
+                                       "id": "0162efc2-0b62-4983-aa1d-d72442008b7c",
+                                       "type": "COMMON"
+                               }
+                       ]
+               }
+       }
+}
diff --git a/bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/SensorServiceDataItem.json b/bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/SensorServiceDataItem.json
new file mode 100644 (file)
index 0000000..316ddb8
--- /dev/null
@@ -0,0 +1,22 @@
+{
+       "id": "638e82cd-774c-4f34-be10-2eec41d1c0a6",
+       "type": "SENSOR",
+       "relationships": {
+               "device": {
+                       "data": {
+                               "id": "638e82cd-774c-4f34-be10-2eec41d1c0a6",
+                               "type": "DEVICE"
+                       }
+               }
+       },
+       "attributes": {
+               "soilHumidity": {
+                       "value": 55,
+                       "timestamp": "2022-06-19T09:30:55.546+00:00"
+               },
+               "soilTemperature": {
+                       "value": 18,
+                       "timestamp": "2022-06-19T09:30:55.747+00:00"
+               }
+       }
+}
diff --git a/bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/SensorServiceDataItemNoAttributes.json b/bundles/org.openhab.binding.gardena/src/test/resources/org/openhab/binding/gardena/SensorServiceDataItemNoAttributes.json
new file mode 100644 (file)
index 0000000..9d111c1
--- /dev/null
@@ -0,0 +1,12 @@
+{
+       "id": "638e82cd-774c-4f34-be10-2eec41d1c0a6",
+       "type": "SENSOR",
+       "relationships": {
+               "device": {
+                       "data": {
+                               "id": "638e82cd-774c-4f34-be10-2eec41d1c0a6",
+                               "type": "DEVICE"
+                       }
+               }
+       }
+}