mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[gardena] Fix null annotation issue (and compiler warning) (#12957)
* 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>
This commit is contained in:
parent
024e15806d
commit
3465e8f30d
@ -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(),
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -12,11 +12,13 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,11 +12,13 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,12 +12,15 @@
|
||||
*/
|
||||
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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -12,11 +12,13 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,11 +12,13 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,11 +12,13 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -12,10 +12,12 @@
|
||||
*/
|
||||
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> {
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "638e82cd-774c-4f34-be10-2eec41d1c0a6",
|
||||
"type": "SENSOR",
|
||||
"relationships": {
|
||||
"device": {
|
||||
"data": {
|
||||
"id": "638e82cd-774c-4f34-be10-2eec41d1c0a6",
|
||||
"type": "DEVICE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user