Commit c83c232166f4ec19e250eea7f1146a7e02ad31d0

Authored by YevhenBondarenko
Committed by Andrew Shvayka
1 parent 2086bd2d

JsonConverter improvements (correct value conversion)

@@ -41,6 +41,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; @@ -41,6 +41,7 @@ import org.thingsboard.server.common.transport.TransportServiceCallback;
41 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 41 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
42 import org.thingsboard.server.common.transport.util.SslUtil; 42 import org.thingsboard.server.common.transport.util.SslUtil;
43 import org.thingsboard.server.gen.transport.TransportProtos; 43 import org.thingsboard.server.gen.transport.TransportProtos;
  44 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
44 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 45 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
45 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials; 46 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
46 import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; 47 import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials;
@@ -61,6 +62,7 @@ import java.util.concurrent.TimeUnit; @@ -61,6 +62,7 @@ import java.util.concurrent.TimeUnit;
61 62
62 @Slf4j 63 @Slf4j
63 @Component 64 @Component
  65 +@TbLwM2mTransportComponent
64 @RequiredArgsConstructor 66 @RequiredArgsConstructor
65 public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier { 67 public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier {
66 68
@@ -228,29 +228,27 @@ public class JsonConverter { @@ -228,29 +228,27 @@ public class JsonConverter {
228 private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key) { 228 private static KeyValueProto buildNumericKeyValueProto(JsonPrimitive value, String key) {
229 String valueAsString = value.getAsString(); 229 String valueAsString = value.getAsString();
230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key); 230 KeyValueProto.Builder builder = KeyValueProto.newBuilder().setKey(key);
231 - if (valueAsString.contains("e") || valueAsString.contains("E")) {  
232 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
233 - var bd = new BigDecimal(valueAsString);  
234 - if (bd.stripTrailingZeros().scale() <= 0) {  
235 - try {  
236 - return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();  
237 - } catch (ArithmeticException e) {  
238 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build(); 231 + var bd = new BigDecimal(valueAsString);
  232 + if (bd.stripTrailingZeros().scale() <= 0) {
  233 + try {
  234 + return builder.setType(KeyValueType.LONG_V).setLongV(bd.longValueExact()).build();
  235 + } catch (ArithmeticException e) {
  236 + if (isTypeCastEnabled) {
  237 + return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
  238 + } else {
  239 + throw new JsonSyntaxException("Big integer values are not supported!");
239 } 240 }
240 - } else {  
241 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();  
242 } 241 }
243 - } else if (valueAsString.contains(".")) {  
244 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(value.getAsDouble()).build();  
245 } else { 242 } else {
246 - try {  
247 - long longValue = Long.parseLong(value.getAsString());  
248 - return builder.setType(KeyValueType.LONG_V).setLongV(longValue).build();  
249 - } catch (NumberFormatException e) {  
250 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
251 - return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(new BigDecimal(valueAsString).doubleValue()).build(); 243 + if (bd.scale() <= 16) {
  244 + return builder.setType(KeyValueType.DOUBLE_V).setDoubleV(bd.doubleValue()).build();
  245 + } else if (isTypeCastEnabled) {
  246 + return builder.setType(KeyValueType.STRING_V).setStringV(bd.toPlainString()).build();
  247 + } else {
  248 + throw new JsonSyntaxException("Big integer values are not supported!");
252 } 249 }
253 } 250 }
  251 +
254 } 252 }
255 253
256 public static TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException { 254 public static TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(JsonElement json, int requestId) throws JsonSyntaxException {
@@ -261,27 +259,24 @@ public class JsonConverter { @@ -261,27 +259,24 @@ public class JsonConverter {
261 private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value) { 259 private static void parseNumericValue(List<KvEntry> result, Entry<String, JsonElement> valueEntry, JsonPrimitive value) {
262 String valueAsString = value.getAsString(); 260 String valueAsString = value.getAsString();
263 String key = valueEntry.getKey(); 261 String key = valueEntry.getKey();
264 - if (valueAsString.contains("e") || valueAsString.contains("E")) {  
265 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
266 - var bd = new BigDecimal(valueAsString);  
267 - if (bd.stripTrailingZeros().scale() <= 0) {  
268 - try {  
269 - result.add(new LongDataEntry(key, bd.longValueExact()));  
270 - } catch (ArithmeticException e) {  
271 - result.add(new DoubleDataEntry(key, bd.doubleValue())); 262 + var bd = new BigDecimal(valueAsString);
  263 + if (bd.stripTrailingZeros().scale() <= 0) {
  264 + try {
  265 + result.add(new LongDataEntry(key, bd.longValueExact()));
  266 + } catch (ArithmeticException e) {
  267 + if (isTypeCastEnabled) {
  268 + result.add(new StringDataEntry(key, bd.toPlainString()));
  269 + } else {
  270 + throw new JsonSyntaxException("Big integer values are not supported!");
272 } 271 }
273 - } else {  
274 - result.add(new DoubleDataEntry(key, bd.doubleValue()));  
275 } 272 }
276 - } else if (valueAsString.contains(".")) {  
277 - result.add(new DoubleDataEntry(key, value.getAsDouble()));  
278 } else { 273 } else {
279 - try {  
280 - long longValue = Long.parseLong(value.getAsString());  
281 - result.add(new LongDataEntry(key, longValue));  
282 - } catch (NumberFormatException e) {  
283 - //TODO: correct value conversion. We should make sure that if the value can't fit into Long or Double, we should send String  
284 - result.add(new DoubleDataEntry(key, new BigDecimal(valueAsString).doubleValue())); 274 + if (bd.scale() <= 16) {
  275 + result.add(new DoubleDataEntry(key, bd.doubleValue()));
  276 + } else if (isTypeCastEnabled) {
  277 + result.add(new StringDataEntry(key, bd.toPlainString()));
  278 + } else {
  279 + throw new JsonSyntaxException("Big integer values are not supported!");
285 } 280 }
286 } 281 }
287 } 282 }
@@ -15,7 +15,9 @@ @@ -15,7 +15,9 @@
15 */ 15 */
16 16
17 import com.google.gson.JsonParser; 17 import com.google.gson.JsonParser;
  18 +import com.google.gson.JsonSyntaxException;
18 import org.junit.Assert; 19 import org.junit.Assert;
  20 +import org.junit.Before;
19 import org.junit.Test; 21 import org.junit.Test;
20 import org.junit.runner.RunWith; 22 import org.junit.runner.RunWith;
21 import org.mockito.junit.MockitoJUnitRunner; 23 import org.mockito.junit.MockitoJUnitRunner;
@@ -28,6 +30,11 @@ public class JsonConverterTest { @@ -28,6 +30,11 @@ public class JsonConverterTest {
28 30
29 private static final JsonParser JSON_PARSER = new JsonParser(); 31 private static final JsonParser JSON_PARSER = new JsonParser();
30 32
  33 + @Before
  34 + public void before() {
  35 + JsonConverter.setTypeCastEnabled(true);
  36 + }
  37 +
31 @Test 38 @Test
32 public void testParseBigDecimalAsLong() { 39 public void testParseBigDecimalAsLong() {
33 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E+1}"), 0L); 40 var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E+1}"), 0L);
@@ -58,4 +65,33 @@ public class JsonConverterTest { @@ -58,4 +65,33 @@ public class JsonConverterTest {
58 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue()); 65 Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue());
59 } 66 }
60 67
  68 + @Test
  69 + public void testParseBigDecimalAsStringOutOfLongRange() {
  70 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
  71 + Assert.assertEquals("99701010061400066000", result.get(0L).get(0).getStrValue().get());
  72 + }
  73 +
  74 + @Test
  75 + public void testParseBigDecimalAsStringOutOfLongRange2() {
  76 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 99701010061400066001}"), 0L);
  77 + Assert.assertEquals("99701010061400066001", result.get(0L).get(0).getStrValue().get());
  78 + }
  79 +
  80 + @Test
  81 + public void testParseBigDecimalAsStringOutOfLongRange3() {
  82 + var result = JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 1E19}"), 0L);
  83 + Assert.assertEquals("10000000000000000000", result.get(0L).get(0).getStrValue().get());
  84 + }
  85 +
  86 + @Test(expected = JsonSyntaxException.class)
  87 + public void testParseBigDecimalOutOfLongRangeWithoutParsing() {
  88 + JsonConverter.setTypeCastEnabled(false);
  89 + JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 89701010051400054084}"), 0L);
  90 + }
  91 +
  92 + @Test(expected = JsonSyntaxException.class)
  93 + public void testParseBigDecimalOutOfLongRangeWithoutParsing2() {
  94 + JsonConverter.setTypeCastEnabled(false);
  95 + JsonConverter.convertToTelemetry(JSON_PARSER.parse("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
  96 + }
61 } 97 }