diff --git a/.github/workflows/test_csharp.yml b/.github/workflows/test_csharp.yml index 48f7b33..06b8bc0 100644 --- a/.github/workflows/test_csharp.yml +++ b/.github/workflows/test_csharp.yml @@ -12,7 +12,7 @@ defaults: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test_java.yml b/.github/workflows/test_java.yml index 0480a00..beca12d 100644 --- a/.github/workflows/test_java.yml +++ b/.github/workflows/test_java.yml @@ -20,7 +20,7 @@ jobs: matrix: # test against latest update of each major Java version, as well as specific updates of LTS versions: # 20, 21还不支持,报错是Source option 7 is no longer supported. Use 8 or later. - java: [7, 8, 11, 17] + java: [8, 11, 17] fail-fast: false steps: diff --git a/csharp/core/Common.cs b/csharp/core/Common.cs index 17298d4..e3f757e 100644 --- a/csharp/core/Common.cs +++ b/csharp/core/Common.cs @@ -190,6 +190,85 @@ public static string ToJSONString(object value) } return JsonConvert.SerializeObject(value); } + + /** + * Transform input as map. + */ + public static Dictionary ParseToMap(object input) + { + if (input == null) + { + return null; + } + + Type type = input.GetType(); + var map = (Dictionary)TeaModelExtensions.ToMapFactory(type, input); + + return map; + } + + public static object ReadPath(object obj, string path) + { + var jsonStr = ToJSONString(ParseToMap(obj)); + var result = JObject.Parse(jsonStr).SelectToken(path); + return ConvertNumber(result); + } + + private static object ConvertNumber(object input) + { + if (input == null) return null; + + var token = input as JToken; + if (token != null) + { + if (token.Type == JTokenType.Integer) + { + return token.ToObject(); + } + if (token.Type == JTokenType.Float) + { + return token.ToObject(); + } + if (token.Type == JTokenType.String) + { + return token.ToString(); + } + if (token.Type == JTokenType.Array) + { + return HandleList(token.Children()); + } + if (token.Type == JTokenType.Object) + { + return HandleMap(token.ToObject>()); + } + if (token.Type == JTokenType.Boolean) + { + return token.ToObject(); + } + } + + return input; + } + + private static object HandleList(IEnumerable list) + { + var convertedList = new List(); + foreach (var item in list) + { + convertedList.Add(ConvertNumber(item)); + } + return convertedList; + } + + private static object HandleMap(IDictionary map) + { + var convertedMap = new Dictionary(); + foreach (var entry in map) + { + convertedMap[entry.Key] = ConvertNumber(entry.Value); + } + return convertedMap; + } public static bool Empty(string val) { diff --git a/csharp/tests/CommonTest.cs b/csharp/tests/CommonTest.cs index 684339e..48e5d06 100644 --- a/csharp/tests/CommonTest.cs +++ b/csharp/tests/CommonTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; using AlibabaCloud.TeaUtil; @@ -483,6 +484,182 @@ public void Test_AssertAsArray() Assert.Throws(() => { Common.AssertAsArray("test"); }); } + + [Fact] + public void Test_ParseToMap() + { + Assert.Null(Common.ParseToMap(null)); + + var context = new Context + { + Str = "test", + ContextInteger = 123, + ContextLong = 123L, + ContextDouble = 1.123d, + ContextFloat = 3.456f, + ContextListLong = new List { 123L, 456L }, + ListList = new List> + { + new List { 789, 123 }, + new List { 8, 9 } + }, + IntegerListMap = new Dictionary> + { + { "integerList", new List { 123, 456 } } + } + }; + + var dicModel = Common.ParseToMap(context); + + Assert.Equal("test", dicModel["testStr"]); + Assert.Equal(123, ((List)((Dictionary)dicModel["integerListMap"])["integerList"])[0]); + Assert.Equal(new List { 789, 123 }, ((List)dicModel["listList"])[0]); + + Dictionary dic = new Dictionary + { + { "model", context } + }; + + var dicMap = Common.ParseToMap(dic); + + Assert.Equal(dicModel, dicMap["model"]); + } + + [Fact] + public void Test_ReadPath() + { + var context = new Context + { + Str = "test", + TestBool = true, + ContextInteger = 123, + ContextLong = 123L, + ContextDouble = 1.123d, + ContextFloat = 3.456f, + ContextListLong = new List { 123L, 456L }, + ListList = new List> + { + new List { 789, 123 }, + new List { 8, 9 } + }, + IntegerListMap = new Dictionary> + { + { "integerList", new List { 123, 456 } } + } + }; + + Assert.Null(Common.ReadPath(context, "$.notExist")); + Assert.True(Common.ReadPath(context, "$.testBool") is bool); + Assert.True(Common.ReadPath(context, "$.listList") is List); + Assert.True(Common.ReadPath(context, "$.contextInteger") is long); + Assert.True(Common.ReadPath(context, "$.contextLong") is long); + Assert.True(Common.ReadPath(context, "$.contextDouble") is double); + Assert.True(Common.ReadPath(context, "$.contextFloat") is double); + Assert.True(Common.ReadPath(context, "$.contextListLong") is List); + Assert.True(Common.ReadPath(context, "$.integerListMap") is Dictionary); + + Assert.Equal(true, Common.ReadPath(context, "$.testBool")); + Assert.Equal("test", Common.ReadPath(context, "$.testStr")); + Assert.Equal(123L, Common.ReadPath(context, "$.contextLong")); + var listLong = Common.ReadPath(context, "$.contextListLong") as List; + Assert.Equal(123L, listLong[0]); + + var listList = Common.ReadPath(context, "$.listList") as List; + Assert.Equal(789L, (listList[0] as List)[0]); + + var map = Common.ReadPath(context, "$.integerListMap") as Dictionary; + Assert.Equal(123L, (map["integerList"] as List)[0]); + + var realListList = new List>(); + foreach (var itemList in listList) + { + var intList = itemList as List; + var nullableIntList = new List(); + if (intList != null) + { + foreach (var item in intList) + { + var intValue = (int?)(item as long?); + nullableIntList.Add(intValue); + } + } + + realListList.Add(nullableIntList); + } + + + var realIntegerListMap = new Dictionary>(); + foreach (var kvp in map) + { + string key = kvp.Key; + object value = kvp.Value; + + var intList = value as List; + var nullableIntList = new List(); + if (intList != null) + { + foreach (var item in intList) + { + nullableIntList.Add((int?)(item as long?)); + } + } + realIntegerListMap[key] = nullableIntList; + } + var context1 = new Context + { + ContextLong = Common.ReadPath(context, "$.contextLong") as long?, + ContextInteger = (int?)(Common.ReadPath(context, "$.contextInteger") as long?), + ContextFloat = (float?)(Common.ReadPath(context, "$.contextFloat") as double?), + ContextDouble = Common.ReadPath(context, "$.contextDouble") as double?, + ContextListLong = (Common.ReadPath(context, "$.contextListLong") as List) + .Select(item => item is long longValue ? longValue : (long?)null) + .ToList(), + ListList = realListList, + IntegerListMap = realIntegerListMap + }; + + Assert.Equal(123L, context1.ContextLong); + Assert.Equal(123, context1.ContextInteger); + Assert.Equal(3.456f, context1.ContextFloat); + Assert.Equal(1.123d, context1.ContextDouble); + Assert.Equal(new List { 123L, 456L }, context1.ContextListLong); + Assert.Equal(new List> + { + new List { 789, 123 }, + new List { 8, 9 } + }, context1.ListList); + Assert.Equal(123, (context1.IntegerListMap["integerList"] as List)[0]); + } + } + + public class Context : TeaModel + { + [NameInMap("testStr")] + public string Str { get; set; } + + [NameInMap("testBool")] + public bool? TestBool { get; set; } + + [NameInMap("contextInteger")] + public int? ContextInteger { get; set; } + + [NameInMap("contextLong")] + public long? ContextLong { get; set; } + + [NameInMap("contextListLong")] + public List ContextListLong { get; set; } + + [NameInMap("listList")] + public List> ListList { get; set; } + + [NameInMap("contextDouble")] + public double? ContextDouble { get; set; } + + [NameInMap("contextFloat")] + public float? ContextFloat { get; set; } + + [NameInMap("integerListMap")] + public Dictionary> IntegerListMap { get; set; } } public class TestRegModel : TeaModel @@ -539,4 +716,4 @@ public class TestRegSubModel : TeaModel public int? testInt { get; set; } } -} +} \ No newline at end of file diff --git a/java/pom.xml b/java/pom.xml index 5f51535..7782c82 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -69,6 +69,11 @@ gson 2.11.0 + + com.jayway.jsonpath + json-path + 2.9.0 + @@ -78,8 +83,8 @@ maven-compiler-plugin 3.6.1 - 7 - 7 + 1.8 + 1.8 diff --git a/java/src/main/java/com/aliyun/teautil/Common.java b/java/src/main/java/com/aliyun/teautil/Common.java index 1bd1834..a0d18ee 100644 --- a/java/src/main/java/com/aliyun/teautil/Common.java +++ b/java/src/main/java/com/aliyun/teautil/Common.java @@ -5,6 +5,7 @@ import com.aliyun.teautil.models.TeaUtilException; import com.google.gson.*; import com.google.gson.reflect.TypeToken; +import com.jayway.jsonpath.JsonPath; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -75,6 +76,50 @@ public static Object parseJSON(String json) { }.getType()); } + public static Map parseToMap(Object o) { + if (null == o) { + return null; + } + return (Map) TeaModel.parseObject(o); + } + + public static T readPath(Object json, String path) { + String jsonStr = toJSONString(parseToMap(json)); + Object result = JsonPath.read(jsonStr, path); + return (T) convertNumber(result); + } + + + private static Object convertNumber(Object input) { + if (input instanceof Integer) { + return Long.valueOf((Integer) input); + } else if (input instanceof List) { + List list = (List) input; + return handleList(list); + } else if (input instanceof Map) { + Map map = (Map) input; + return handleMap(map); + } + return input; + } + + private static List handleList(List list) { + List longList = new ArrayList<>(); + for (Object item : list) { + longList.add(convertNumber(item)); + } + return longList; + } + + private static Map handleMap(Map map) { + Map longMap = new LinkedHashMap<>(); + for (Map.Entry entry : map.entrySet()) { + String key = (String) entry.getKey(); + longMap.put(key, convertNumber(entry.getValue())); + } + return longMap; + } + /** * Assert a value, if it is a map, it, otherwise throws * diff --git a/java/src/test/java/com/aliyun/teautil/CommonTest.java b/java/src/test/java/com/aliyun/teautil/CommonTest.java index 3a9de53..95b0dcc 100644 --- a/java/src/test/java/com/aliyun/teautil/CommonTest.java +++ b/java/src/test/java/com/aliyun/teautil/CommonTest.java @@ -1,5 +1,6 @@ package com.aliyun.teautil; +import com.aliyun.tea.NameInMap; import com.aliyun.tea.TeaModel; import com.aliyun.tea.TeaRequest; import com.aliyun.teautil.models.RuntimeOptions; @@ -438,4 +439,208 @@ public void assertAsReadableTest() throws Exception { InputStream inputStream = new ByteArrayInputStream("test".getBytes("UTF-8")); Assert.assertEquals(inputStream, Common.assertAsReadable(inputStream)); } + + @Test + public void stringifyTest() { + Context context = new Context(); + context.setTestBool(true); + context.setContextInteger(123); + context.setContextLong(123L); + context.setContextDouble(1.123); + context.setContextFloat(3.456f); + context.setContextListLong(Arrays.asList(123L, 456L)); + Map> integerListMap = new HashMap<>(); + List integerList = Arrays.asList(123, 456); + integerListMap.put("integerList", integerList); + context.setIntegerListMap(integerListMap); + + List integerList1 = Arrays.asList(789, 123); + List> listList = Arrays.asList(integerList, integerList1); + context.setContextListList(listList); + + String str = Common.toJSONString(context); + Assert.assertEquals("{\"testBool\":true,\"contextInteger\":123,\"contextLong\":123,\"contextListLong\":[123,456],\"listList\":[[123,456],[789,123]],\"contextDouble\":1.123,\"contextFloat\":3.456,\"integerListMap\":{\"integerList\":[123,456]}}", str); + } + + @Test + public void parseJSONTest() { + String context = "{\"contextHtml\": \"world\" ,\"contextInteger\":123,\"contextLong\":123,\"contextListLong\":[123,456],\"listList\":[[123,456],[789,123]],\"contextDouble\":1.123,\"contextFloat\":3.456,\"integerListMap\":{\"integerList\":[123,456]}}"; + Map res = (Map) Common.parseJSON(context); + Assert.assertEquals("world", res.get("contextHtml")); + Assert.assertEquals(123L, res.get("contextInteger")); + Assert.assertEquals(3.456d, res.get("contextFloat")); + Assert.assertEquals(Arrays.asList(123L, 456L), res.get("contextListLong")); + } + + @Test + public void parseToMapTest() { + Assert.assertNull(Common.parseToMap(null)); + Context context = new Context(); + context.setStr("test"); + context.setContextInteger(123); + context.setContextLong(123L); + context.setContextDouble(1.123); + context.setContextFloat(3.456f); + context.setContextListLong(Arrays.asList(123L, 456L)); + Map> integerListMap = new HashMap<>(); + List integerList = Arrays.asList(123, 456); + integerListMap.put("integerList", integerList); + context.setIntegerListMap(integerListMap); + + List integerList1 = Arrays.asList(789, 123); + List> listList = Arrays.asList(integerList, integerList1); + context.setContextListList(listList); + + Map result = Common.parseToMap(context); + Assert.assertEquals("test", result.get("testStr")); + Assert.assertEquals(123, result.get("contextInteger")); + int i = (int)((List)((Map)result.get("integerListMap")).get("integerList")).get(0); + Assert.assertEquals(123, i); + + Map dic = new HashMap<>(); + dic.put("model", context); + Map res = Common.parseToMap(dic); + Assert.assertEquals(result, res.get("model")); + } + + @Test + public void readPathTest() { + Context context = new Context(); + context.setTestBool(true); + context.setContextInteger(123); + context.setContextLong(123L); + context.setContextDouble(1.123); + context.setContextFloat(3.456f); + context.setContextListLong(Arrays.asList(123L, 456L)); + Map> integerListMap = new HashMap<>(); + List integerList = Arrays.asList(123, 456); + integerListMap.put("integerList", integerList); + context.setIntegerListMap(integerListMap); + + List integerList1 = Arrays.asList(789, 123); + List> listList = Arrays.asList(integerList, integerList1); + context.setContextListList(listList); + + Assert.assertTrue(Common.readPath(context, "$.testBool")); + Assert.assertTrue(Common.readPath(context, "$.listList") instanceof List); + Assert.assertTrue(Common.readPath(context, "$.contextInteger") instanceof Long); + Assert.assertTrue(Common.readPath(context, "$.contextLong") instanceof Long); + Assert.assertTrue(Common.readPath(context, "$.contextDouble") instanceof Double); + Assert.assertTrue(Common.readPath(context, "$.contextFloat") instanceof Double); + Assert.assertTrue(Common.readPath(context, "$.contextListLong") instanceof List); + Assert.assertTrue(Common.readPath(context, "$.integerListMap") instanceof Map); + List list = Common.readPath(context, "$.contextListLong"); + Assert.assertEquals(123L, list.get(0).longValue()); + + List> listList1 = Common.readPath(context, "$.listList"); + Assert.assertEquals(123L, listList1.get(0).get(0).longValue()); + + Map> map = Common.readPath(context, "$.integerListMap"); + Assert.assertEquals(123L, map.get("integerList").get(0).longValue()); + + + Context context1 = new Context(); + context1.setContextListLong(Common.readPath(context, "$.contextListLong")); + context1.setIntegerListMap(Common.readPath(context, "$.integerListMap")); + context1.setContextLong(Common.readPath(context, "$.contextLong")); + context1.setContextDouble(Common.readPath(context, "$.contextDouble")); + context1.setContextInteger(((Long) Common.readPath(context, "$.contextInteger")).intValue()); + context1.setContextFloat(((Double) Common.readPath(context, "$.contextFloat")).floatValue()); + } + + public class Context extends TeaModel{ + @NameInMap("testStr") + public String str; + public boolean testBool; + + public Integer contextInteger; + public Long contextLong; + public List contextListLong; + public List> listList; + public Double contextDouble; + public Float contextFloat; + + public Map> integerListMap; + + public Context setStr(String str) { + this.str = str; + return this; + } + + public String getStr() { + return this.str; + } + + public Context setTestBool(boolean testBool) { + this.testBool = testBool; + return this; + } + + public boolean getTestBool() { + return this.testBool; + } + + public Context setContextInteger(Integer contextInteger) { + this.contextInteger = contextInteger; + return this; + } + + public Integer getContextInteger() { + return this.contextInteger; + } + + public Context setContextLong(Long contextLong) { + this.contextLong = contextLong; + return this; + } + + public Long getContextLong() { + return this.contextLong; + } + + public Context setContextListLong(List contextListLong) { + this.contextListLong = contextListLong; + return this; + } + + public List getContextListLong() { + return this.contextListLong; + } + + public Context setContextListList(List> listList) { + this.listList = listList; + return this; + } + + public List> getContextListList() { + return this.listList; + } + + public Context setContextDouble(Double contextDouble) { + this.contextDouble = contextDouble; + return this; + } + + public Double getContextDouble() { + return this.contextDouble; + } + + public Context setContextFloat(Float contextFloat) { + this.contextFloat = contextFloat; + return this; + } + + public Float getContextFloat() { + return this.contextFloat; + } + + public Context setIntegerListMap(Map> integerListMap) { + this.integerListMap = integerListMap; + return this; + } + + public Map> getIntegerListMap() { + return this.integerListMap; + } + } } diff --git a/main.tea b/main.tea index a418201..24e6d32 100644 --- a/main.tea +++ b/main.tea @@ -49,6 +49,14 @@ static function toString(val: bytes): string; */ static function parseJSON(val: string): any; +/** + * Give a json object and a path, read value with the path + * @param json The json object + * @param path The path string + * @return value of json object with the path + */ +static function readPath(json: any, path: string): any; + /** * Read data from a readable stream, and compose it to a bytes * @param stream the readable stream