From 03d94c77d7cf5ef618f17ad4e0fd72cf67f9bb85 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 20 Apr 2023 10:06:55 +0300 Subject: [PATCH] Added new function to TBEL helper --- .../thingsboard/script/api/tbel/TbUtils.java | 64 +++++++++++++++++ .../script/api/tbel/TbUtilsTest.java | 70 +++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index fa75709d83..c4f86f80a3 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -18,7 +18,9 @@ package org.thingsboard.script.api.tbel; import org.mvel2.ExecutionContext; import org.mvel2.ParserConfiguration; import org.mvel2.execution.ExecutionArrayList; +import org.mvel2.execution.ExecutionHashMap; import org.mvel2.util.MethodStub; +import org.thingsboard.server.common.data.StringUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -27,8 +29,13 @@ import java.math.RoundingMode; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Base64; +import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; public class TbUtils { @@ -89,6 +96,14 @@ public class TbUtils { byte[].class))); parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex", ExecutionArrayList.class))); + parserConfig.addImport("toFlatMap", new MethodStub(TbUtils.class.getMethod("toFlatMap", + Object.class, HashMap.class))); + parserConfig.addImport("toFlatMap", new MethodStub(TbUtils.class.getMethod("toFlatMap", + Object.class, HashMap.class, boolean.class))); + parserConfig.addImport("toFlatMap", new MethodStub(TbUtils.class.getMethod("toFlatMap", + Object.class, HashMap.class, List.class))); + parserConfig.addImport("toFlatMap", new MethodStub(TbUtils.class.getMethod("toFlatMap", + Object.class, HashMap.class, List.class, boolean.class))); } public static String btoa(String input) { @@ -316,4 +331,53 @@ public class TbUtils { } return value; } + + public static void toFlatMap(Object json, HashMap map) { + toFlatMap(json, map, new ArrayList<>(), true); + } + + public static void toFlatMap(Object json, HashMap map, boolean pathInKey) { + toFlatMap(json, map, new ArrayList<>(), pathInKey); + } + + public static void toFlatMap(Object json, HashMap map, List excludeList) { + toFlatMap(json, map, excludeList, true); + } + + public static void toFlatMap(Object json, HashMap map, List excludeList, boolean pathInKey) { + parseRecursive(json, map, excludeList, "", pathInKey); + } + + private static void parseRecursive(Object json, HashMap map, List excludeList, String path, boolean pathInKey) { + if (json instanceof Map.Entry) { + Map.Entry entry = (Map.Entry) json; + if (StringUtils.isNotBlank(path)) { + path += "."; + } + if (excludeList.contains(entry.getKey())) { + return; + } + path += entry.getKey(); + json = entry.getValue(); + } + if (json instanceof Set || json instanceof List) { + String arrayPath = path + "."; + Object[] collection = ((Collection) json).toArray(); + for (int index = 0; index < collection.length; index++) { + parseRecursive(collection[index], map, excludeList, arrayPath + index, pathInKey); + } + } else if (json instanceof Map) { + Map node = (Map) json; + for (Map.Entry entry : node.entrySet()) { + parseRecursive(entry, map, excludeList, path, pathInKey); + } + } else { + if (pathInKey) { + map.put(path, json); + } else { + String key = path.contains(".") ? path.substring(path.lastIndexOf('.') + 1) : path; + map.put(key, json); + } + } + } } diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index f4cd610b72..af10b7b49b 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -20,7 +20,9 @@ import org.junit.Test; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class TbUtilsTest { @@ -87,6 +89,74 @@ public class TbUtilsTest { Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false)); } + @Test + public void toFlatMap() { + HashMap inputMap = new HashMap<>(); + inputMap.put("name", "Alice"); + inputMap.put("age", 30); + inputMap.put("devices", List.of( + new HashMap() {{ + put("id", "dev001"); + put("type", "sensor"); + }}, + new HashMap() {{ + put("id", "dev002"); + put("type", "actuator"); + }} + )); + inputMap.put("settings", new HashMap() {{ + put("notifications", true); + put("timezone", "UTC-5"); + put("params", new HashMap() {{ + put("param1", "value1"); + put("param2", "value2"); + put("param3", new HashMap() {{ + put("subParam1", "value1"); + put("subParam2", "value2"); + }}); + }}); + }}); + + List excludeList = List.of("age", "id", "param1", "subParam2"); + + HashMap expectedMapWithPath = new HashMap<>(); + expectedMapWithPath.put("name", "Alice"); + expectedMapWithPath.put("devices.0.type", "sensor"); + expectedMapWithPath.put("devices.1.type", "actuator"); + expectedMapWithPath.put("settings.notifications", true); + expectedMapWithPath.put("settings.timezone", "UTC-5"); + expectedMapWithPath.put("settings.params.param2", "value2"); + expectedMapWithPath.put("settings.params.param3.subParam1", "value1"); + + HashMap actualMapWithPaths = new HashMap<>(); + TbUtils.toFlatMap(inputMap, actualMapWithPaths, excludeList, true); + + Assert.assertEquals(expectedMapWithPath, actualMapWithPaths); + + HashMap expectedMapWithoutPaths = new HashMap<>(); + expectedMapWithoutPaths.put("timezone", "UTC-5"); + expectedMapWithoutPaths.put("name", "Alice"); + expectedMapWithoutPaths.put("id", "dev002"); + expectedMapWithoutPaths.put("subParam2", "value2"); + expectedMapWithoutPaths.put("type", "actuator"); + expectedMapWithoutPaths.put("subParam1", "value1"); + expectedMapWithoutPaths.put("param1", "value1"); + expectedMapWithoutPaths.put("notifications", true); + expectedMapWithoutPaths.put("age", 30); + expectedMapWithoutPaths.put("param2", "value2"); + + HashMap actualMapWithoutPaths = new HashMap<>(); + TbUtils.toFlatMap(inputMap, actualMapWithoutPaths, new ArrayList<>(), false); + + Assert.assertEquals(expectedMapWithoutPaths, actualMapWithoutPaths); + } + + + + private static String keyToValue(String key, String extraSymbol) { + return key + "Value" + (extraSymbol == null ? "" : extraSymbol); + } + private static List toList(byte[] data) { List result = new ArrayList<>(data.length); for (Byte b : data) {