]> git.basschouten.com Git - openhab-addons.git/blob
22bdf67bc9f1d1a93e4545a8f7e2eec532e23734
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.surepetcare.internal.utils;
14
15 import java.io.IOException;
16 import java.util.List;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.binding.surepetcare.internal.dto.SurePetcareDeviceCurfew;
21 import org.openhab.binding.surepetcare.internal.dto.SurePetcareDeviceCurfewList;
22
23 import com.google.gson.Gson;
24 import com.google.gson.TypeAdapter;
25 import com.google.gson.TypeAdapterFactory;
26 import com.google.gson.reflect.TypeToken;
27 import com.google.gson.stream.JsonReader;
28 import com.google.gson.stream.JsonToken;
29 import com.google.gson.stream.JsonWriter;
30 import com.google.gson.stream.MalformedJsonException;
31
32 /**
33  * The {@link SurePetcareDeviceCurfewListTypeAdapterFactory} class is a custom TypeAdapter factory to ensure
34  * deserialization always returns a list even if the Json document contains only a single curfew object and
35  * not an array.
36  *
37  * See https://stackoverflow.com/questions/43412261/make-gson-accept-single-objects-where-it-expects-arrays
38  *
39  * @author Rene Scherer - Initial contribution
40  */
41 @NonNullByDefault
42 public final class SurePetcareDeviceCurfewListTypeAdapterFactory<E> implements TypeAdapterFactory {
43
44     // Gson can instantiate it itself
45     private SurePetcareDeviceCurfewListTypeAdapterFactory() {
46     }
47
48     @Override
49     public @Nullable <T> TypeAdapter<T> create(final @Nullable Gson gson, final @Nullable TypeToken<T> typeToken) {
50         if (gson == null || typeToken == null) {
51             return null;
52         }
53         final TypeAdapter<SurePetcareDeviceCurfew> elementTypeAdapter = gson
54                 .getAdapter(TypeToken.get(SurePetcareDeviceCurfew.class));
55         @SuppressWarnings("unchecked")
56         final TypeAdapter<T> alwaysListTypeAdapter = (TypeAdapter<T>) new SurePetcareDeviceCurfewListTypeAdapter(
57                 elementTypeAdapter).nullSafe();
58         return alwaysListTypeAdapter;
59     }
60
61     private static final class SurePetcareDeviceCurfewListTypeAdapter
62             extends TypeAdapter<List<SurePetcareDeviceCurfew>> {
63
64         private final TypeAdapter<SurePetcareDeviceCurfew> elementTypeAdapter;
65
66         private SurePetcareDeviceCurfewListTypeAdapter(final TypeAdapter<SurePetcareDeviceCurfew> elementTypeAdapter) {
67             this.elementTypeAdapter = elementTypeAdapter;
68         }
69
70         @Override
71         public void write(final @Nullable JsonWriter out, @Nullable final List<SurePetcareDeviceCurfew> list)
72                 throws IOException {
73             if (out != null && list != null) {
74                 out.beginArray();
75                 for (SurePetcareDeviceCurfew curfew : list) {
76                     elementTypeAdapter.write(out, curfew);
77                 }
78                 out.endArray();
79             }
80         }
81
82         @Override
83         public @Nullable List<SurePetcareDeviceCurfew> read(final @Nullable JsonReader in) throws IOException {
84             // This is where we detect the list "type"
85             final SurePetcareDeviceCurfewList list = new SurePetcareDeviceCurfewList();
86             if (in != null) {
87                 final JsonToken token = in.peek();
88                 switch (token) {
89                     case BEGIN_ARRAY:
90                         // If it's a regular list, just consume [, <all elements>, and ]
91                         in.beginArray();
92                         while (in.hasNext()) {
93                             SurePetcareDeviceCurfew cf = elementTypeAdapter.read(in);
94                             if (cf != null) {
95                                 list.add(cf);
96                             }
97                         }
98                         in.endArray();
99                         break;
100                     case BEGIN_OBJECT:
101                         SurePetcareDeviceCurfew cf = elementTypeAdapter.read(in);
102                         if (cf != null) {
103                             list.add(cf);
104                         }
105                         break;
106                     case NULL:
107                         throw new AssertionError(
108                                 "Must never happen: check if the type adapter configured with .nullSafe()");
109                     case STRING:
110                     case NUMBER:
111                     case BOOLEAN:
112                     case NAME:
113                     case END_ARRAY:
114                     case END_OBJECT:
115                     case END_DOCUMENT:
116                         throw new MalformedJsonException("Unexpected token: " + token);
117                     default:
118                         throw new AssertionError("Must never happen: " + token);
119                 }
120             }
121             return list;
122         }
123     }
124 }