diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 405be5cf..2a09a4ae 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -320,6 +320,8 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 13123 DoubleKillTest: bad SpEL, check null * 13124 JsonHelperCompatibleTest: fastjson basic type compatible * 13125 JsonHelperCompatibleTest: jackson basic type compatible +* 13126 FastJsonTest: fastjson helper json path +* 13127 TypeReferenceTest: TypeReference, TypeDescriptor, ResolvableType ## 14 Warlock diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java index bdd28387..efd8bd97 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java @@ -41,16 +41,16 @@ public class TypeSugar { // - private static final ConcurrentHashMap CacheResolvable = new ConcurrentHashMap<>(); - private static final ConcurrentHashMap CacheDescriptor = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap CacheResolvable = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap CacheDescriptor = new ConcurrentHashMap<>(); /** * by cache */ @NotNull public static TypeDescriptor describe(@NotNull Class clazz, Class... generics) { - ArrayKey key = generics == null || generics.length == 0 - ? new ArrayKey(clazz) + Object key = generics == null || generics.length == 0 + ? clazz : new ArrayKey(clazz, generics); return CacheDescriptor.computeIfAbsent(key, ignore -> describeNew(clazz, generics)); } @@ -60,8 +60,8 @@ public static TypeDescriptor describe(@NotNull Class clazz, Class... gener */ @NotNull public static ResolvableType resolve(@NotNull Class clazz, Class... generics) { - ArrayKey key = generics == null || generics.length == 0 - ? new ArrayKey(clazz) + Object key = generics == null || generics.length == 0 + ? clazz : new ArrayKey(clazz, generics); return CacheResolvable.computeIfAbsent(key, ignore -> resolveNew(clazz, generics)); } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java index b73e0a0d..85d80c03 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java @@ -1,8 +1,10 @@ package pro.fessional.wings.slardar.spring.bean; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.fasterxml.jackson.databind.ser.std.DateSerializer; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer; @@ -10,6 +12,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.ApplicationContext; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -264,17 +267,25 @@ public SimpleFilterProvider jacksonFilterProvider(List { log.info("SlardarWebmvc spring-conf JacksonHelper.initGlobal"); new JacksonHelper() {{ + var builder = context.getBean(Jackson2ObjectMapperBuilder.class); + + // wings bindXmlWings(builder.createXmlMapper(true).build()); bindJsonWings(builder.createXmlMapper(false).build()); - bindXmlBean(builder.createXmlMapper(true).build()); - bindJsonBean(builder.createXmlMapper(false).build()); + // bean + var jsonBean = context.getBeanProvider(ObjectMapper.class); + bindJsonBean(jsonBean.getIfAvailable(() -> context.getBean(ObjectMapper.class))); + var xmlBean = context.getBeanProvider(XmlMapper.class); + bindXmlBean(xmlBean.getIfAvailable(() -> builder.createXmlMapper(true).build())); + // at last, restore createXmlMapper to false + builder.createXmlMapper(false); }}; }); } diff --git a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/JsonHelperCompatibleTest.java b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/JsonHelperCompatibleTest.java index a22d50fe..c736b991 100644 --- a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/JsonHelperCompatibleTest.java +++ b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/JsonHelperCompatibleTest.java @@ -22,6 +22,12 @@ import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; /** * Ø @@ -85,9 +91,39 @@ public void testFastjson() { fastjson(CommonValue.OdtValueUs, "\"2023-04-05T06:07:08-04:00\""); fastjson(CommonValue.OdtValueJp, "\"2023-04-05T06:07:08+09:00\""); + fastjson(BoxingArray.BoolArrEmpty); + fastjson(BoxingArray.BoolArrValue); + fastjson(BoxingArray.ByteArrEmpty); + fastjson(BoxingArray.ByteArrValue); + fastjson(BoxingArray.CharArrEmpty); + fastjson(BoxingArray.CharArrValue); + fastjson(BoxingArray.ShortArrEmpty); + fastjson(BoxingArray.ShortArrValue); + fastjson(BoxingArray.IntArrEmpty); + fastjson(BoxingArray.IntArrValue); + fastjson(BoxingArray.LongArrEmpty); + fastjson(BoxingArray.LongArrValue); + fastjson(BoxingArray.FloatArrEmpty); + fastjson(BoxingArray.FloatArrValue); + fastjson(BoxingArray.DoubleArrEmpty); + fastjson(BoxingArray.DoubleArrValue); + + fastjson(CollectionValue.EmptyList); + fastjson(CollectionValue.EmptySet); + fastjson(CollectionValue.EmptyMap); + fastjson(CollectionValue.BoolList); + fastjson(CollectionValue.BoolSet); + fastjson(CollectionValue.BoolMap); + fastjson(CollectionValue.LongList); + fastjson(CollectionValue.LongSet); + fastjson(CollectionValue.LongMap); + fastjson(CollectionValue.DoubleList); + fastjson(CollectionValue.DoubleSet); + fastjson(CollectionValue.DoubleMap); + // fastjson(new CommonValue().defaults(), "\"offsetDateTimeValueUs\":\"2023-04-05T06:07:08-04:00\"", "\"zoneDateTimeValueUs\":\"2023-04-05T06:07:08[America/New_York]\""); - fastjson(new CollectionValue().defaults(), "\"boolList\":[true,false]", "\"boolMap\":{\"0\":true,\"1\":false}"); // MAP NOT WORKS + fastjson(new CollectionValue().defaults(), "\"boolList\":[true,false]", "\"boolMap\":{\"k0\":true,\"k1\":false}"); // MAP NOT WORKS fastjson(new BoxingValue().defaults(), "\"boolTrue\":true", "\"intMin\":-2147483648"); fastjson(new PrimitiveValue().defaults(), "\"boolTrue\":true", "\"intMin\":-2147483648"); fastjson(new BoxingArray().defaults(), "\"boolArrValue\":[true,false]", "\"intArrValue\":[-2147483648,2147483647]"); @@ -111,26 +147,100 @@ private void fastjson(T t1, T t2, String... ins) { final String jsonByFastWings = FastJsonHelper.string(t1); if (ins == null || ins.length == 0) { + ins = new String[]{}; log.info("jsonByFastWings={}, class={}", jsonByFastWings, clz.getSimpleName()); } else { log.info("jsonByFastWings={}, class={}, ins-len={}", jsonByFastWings, clz.getSimpleName(), ins.length); - for (String s : ins) { - if (asserts) Assertions.assertTrue(jsonByFastWings.equals(s) || jsonByFastWings.contains(s), s + " not found"); - } } + final Object objectByFastWings1 = FastJsonHelper.object(jsonByFastWings, clz); - if (asserts) Assertions.assertEquals(t2, objectByFastWings1); final Object objectByFastWings2 = FastJsonHelper.object(jsonByFastPlain, clz); - if (asserts) Assertions.assertEquals(t2, objectByFastWings2); final Object objectByFastPlain = JSON.parseObject(jsonByFastWings, clz); - if (asserts) Assertions.assertEquals(t2, objectByFastPlain); - // read by jackson Object objectByJackWings = JacksonHelper.object(jsonByFastWings, clz); - if (asserts) Assertions.assertEquals(t2, fixFastWingsJack(objectByJackWings)); - Object objectByJackPlain = JacksonHelper.object(fixFastWingsJackPlain(clz, jsonByFastWings), clz, Style.Plain); - if (asserts) Assertions.assertEquals(t2, fixFastWingsJack(objectByJackPlain)); + Object objectByJackPlain = JacksonHelper.object(Style.Plain, fixFastWingsJackPlain(clz, jsonByFastWings), clz); + + if (!asserts) return; + + for (String s : ins) { + Assertions.assertTrue(jsonByFastWings.equals(s) || jsonByFastWings.contains(s), s + " not found"); + } + + if (clz.isArray()) { + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByFastWings1); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByFastWings2); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByFastPlain); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) fixFastWingsJack(objectByJackWings)); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) fixFastWingsJack(objectByJackPlain)); + } + else { + + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByFastWings1)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByFastWings2)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByFastPlain)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, fixFastWingsJack(objectByJackWings))); + Assertions.assertEquals(t2, fixCollectionValueType(t2, fixFastWingsJack(objectByJackPlain))); + } + } + + @SuppressWarnings("all") + private Object fixCollectionValueType(Object t2, Object obj) { + if (t2 instanceof List ts && !ts.isEmpty() && obj instanceof List cs) { + Object v0 = ts.get(0); + Function fun = null; + if (v0 instanceof Long) { + fun = Long::valueOf; + } + else if (v0 instanceof Double) { + fun = Double::valueOf; + } + + if (fun != null) { + ArrayList tmp = new ArrayList<>(cs); + cs.clear(); + for (Object o : tmp) { + cs.add(fun.apply(o.toString())); + } + } + } + else if (t2 instanceof Set ts && !ts.isEmpty() && obj instanceof Set cs) { + Object v0 = ts.iterator().next(); + Function fun = null; + if (v0 instanceof Long) { + fun = Long::valueOf; + } + else if (v0 instanceof Double) { + fun = Double::valueOf; + } + + if (fun != null) { + ArrayList tmp = new ArrayList<>(cs); + cs.clear(); + for (Object o : tmp) { + cs.add(fun.apply(o.toString())); + } + } + } + else if (t2 instanceof Map ts && !ts.isEmpty() && obj instanceof Map cs) { + Object v0 = ts.values().iterator().next(); + Function fun = null; + if (v0 instanceof Long) { + fun = Long::valueOf; + } + else if (v0 instanceof Double) { + fun = Double::valueOf; + } + + if (fun != null) { + HashMap tmp = new HashMap<>(cs); + cs.clear(); + for (Map.Entry en : tmp.entrySet()) { + cs.put(en.getKey(), fun.apply(en.getValue().toString())); + } + } + } + return obj; } private String fixFastWingsJackPlain(Class clz, String json) { @@ -200,8 +310,38 @@ public void testJackson() { jackson(CommonValue.OdtValueUs, "\"2023-04-05 06:07:08 -04:00\""); jackson(CommonValue.OdtValueJp, "\"2023-04-05 06:07:08 +09:00\""); + jackson(BoxingArray.BoolArrEmpty); + jackson(BoxingArray.BoolArrValue); + jackson(BoxingArray.ByteArrEmpty); + jackson(BoxingArray.ByteArrValue); + jackson(BoxingArray.CharArrEmpty); + jackson(BoxingArray.CharArrValue); + jackson(BoxingArray.ShortArrEmpty); + jackson(BoxingArray.ShortArrValue); + jackson(BoxingArray.IntArrEmpty); + jackson(BoxingArray.IntArrValue); + jackson(BoxingArray.LongArrEmpty); + jackson(BoxingArray.LongArrValue); + jackson(BoxingArray.FloatArrEmpty); + jackson(BoxingArray.FloatArrValue); + jackson(BoxingArray.DoubleArrEmpty); + jackson(BoxingArray.DoubleArrValue); + + jackson(CollectionValue.EmptyList); + jackson(CollectionValue.EmptySet); + jackson(CollectionValue.EmptyMap); + jackson(CollectionValue.BoolList); + jackson(CollectionValue.BoolSet); + jackson(CollectionValue.BoolMap); + jackson(CollectionValue.LongList); + jackson(CollectionValue.LongSet); + jackson(CollectionValue.LongMap); + jackson(CollectionValue.DoubleList); + jackson(CollectionValue.DoubleSet); + jackson(CollectionValue.DoubleMap); + jackson(new CommonValue().defaults(), "\"offsetDateTimeValueUs\":\"2023-04-05 06:07:08 -04:00\"", "\"zoneDateTimeValueUs\":\"2023-04-05 06:07:08 America/New_York\""); - jackson(new CollectionValue().defaults(), "\"boolList\":[true,false]", "\"boolMap\":{\"0\":true,\"1\":false}"); // MAP NOT WORKS + jackson(new CollectionValue().defaults(), "\"boolList\":[true,false]", "\"boolMap\":{\"k0\":true,\"k1\":false}"); // MAP NOT WORKS jackson(new BoxingValue().defaults(), "\"boolTrue\":true", "\"intMin\":-2147483648"); jackson(new PrimitiveValue().defaults(), "\"boolTrue\":true", "\"intMin\":-2147483648"); jackson(new BoxingArray().defaults(), "\"boolArrValue\":[true,false]", "\"intArrValue\":[-2147483648,2147483647]"); @@ -218,32 +358,46 @@ private void jackson(T t1, String... ins) { private void jackson(T t1, T t2, String... ins) { log.info("jackson, value={}", t1); - final String jsonByJackPlain = JacksonHelper.string(t1, Style.Plain); + final String jsonByJackPlain = JacksonHelper.string(Style.Plain, t1); log.info("jsonByJackPlain={}", jsonByJackPlain); final String jsonByJackWings = JacksonHelper.string(t1); Class clz = t1.getClass(); if (ins == null || ins.length == 0) { + ins = new String[]{}; log.info("jsonByJackWings={}, class={}", jsonByJackWings, clz.getSimpleName()); } else { log.info("jsonByJackWings={}, class={}, ins-len={}", jsonByJackWings, clz.getSimpleName(), ins.length); - for (String s : ins) { - if (asserts) Assertions.assertTrue(jsonByJackWings.equals(s) || jsonByJackWings.contains(s), s + " not found"); - } } + final Object objectByJackWings1 = JacksonHelper.object(jsonByJackWings, clz); - if (asserts) Assertions.assertEquals(t2, objectByJackWings1); final Object objectByJackWings2 = JacksonHelper.object(jsonByJackPlain, clz); - if (asserts) Assertions.assertEquals(t2, objectByJackWings2); - final Object objectByJackPlain = JacksonHelper.object(jsonByJackWings, clz, Style.Plain); - if (asserts) Assertions.assertEquals(t2, objectByJackPlain); - + final Object objectByJackPlain = JacksonHelper.object(Style.Plain, jsonByJackWings, clz); // read by fastjson final Object objectByFastWings = FastJsonHelper.object(fixJackWingsFastWings(clz, jsonByJackWings), clz); - if (asserts) Assertions.assertEquals(t2, objectByFastWings); final Object objectByFastPlain = JSON.parseObject(fixJackWingsFastWings(clz, jsonByJackWings), clz); - if (asserts) Assertions.assertEquals(t2, objectByFastPlain); + + if (!asserts) return; + + for (String s : ins) { + Assertions.assertTrue(jsonByJackWings.equals(s) || jsonByJackWings.contains(s), s + " not found"); + } + + if (clz.isArray()) { + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByJackWings1); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByJackWings2); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByJackPlain); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByFastWings); + Assertions.assertArrayEquals((Object[]) t2, (Object[]) objectByFastPlain); + } + else { + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByJackWings1)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByJackWings2)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByJackPlain)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByFastWings)); + Assertions.assertEquals(t2, fixCollectionValueType(t2, objectByFastPlain)); + } } private String fixJackWingsFastWings(Class clz, String json) { diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java index 7b1dba75..d390553e 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java @@ -2,16 +2,21 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; +import com.alibaba.fastjson2.JSONPath; import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.JSONWriter; -import com.alibaba.fastjson2.TypeReference; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; +import pro.fessional.mirana.lock.ArrayKey; +import pro.fessional.wings.silencer.enhance.TypeSugar; import java.io.InputStream; import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; /** *
@@ -50,6 +55,17 @@ public class FastJsonHelper {
 //        JSONWriter.Feature.WriteNonStringValueAsString, // https://github.com/alibaba/fastjson2/issues/2560
     };
 
+
+    /**
+     * do NOT modify these
+     * jsonpath_cn
+     */
+    public static final JSONPath.Feature[] WingsPath = {
+        JSONPath.Feature.NullOnError
+    };
+
+    public static final long WingsPathMask = featureMask(WingsPath);
+
     /**
      * Deserialization with the wings convention
      */
@@ -68,15 +84,6 @@ public static  T object(String json, @NotNull TypeDescriptor targetType) {
         return JSON.parseObject(json, targetType.getResolvableType().getType(), WingsReader);
     }
 
-    /**
-     * Deserialization with the wings convention
-     */
-    @Contract("!null,_->!null")
-    public static  T object(String json, @NotNull TypeReference targetType) {
-        if (json == null) return null;
-        return JSON.parseObject(json, targetType, WingsReader);
-    }
-
     /**
      * Deserialization with the wings convention
      */
@@ -89,12 +96,14 @@ public static  T object(String json, @NotNull Type targetType) {
     /**
      * Deserialization with the wings convention
      */
-    @Contract("!null,_->!null")
-    public static  T object(String json, @NotNull Class targetType) {
+    @Contract("!null,_,_->!null")
+    public static  T object(String json, @NotNull Class targetType, Class... generics) {
         if (json == null) return null;
-        return JSON.parseObject(json, targetType, WingsReader);
+        Type genericType = TypeSugar.type(targetType, generics);
+        return JSON.parseObject(json, genericType, WingsReader);
     }
 
+
     /**
      * Deserialization with the wings convention
      */
@@ -134,10 +143,11 @@ public static  T object(InputStream json, @NotNull Type targetType) {
     /**
      * Deserialization with the wings convention
      */
-    @Contract("!null,_->!null")
-    public static  T object(InputStream json, @NotNull Class targetType) {
+    @Contract("!null,_,_->!null")
+    public static  T object(InputStream json, @NotNull Class targetType, Class... generics) {
         if (json == null) return null;
-        return JSON.parseObject(json, targetType, WingsReader);
+        Type genericType = TypeSugar.type(targetType, generics);
+        return JSON.parseObject(json, genericType, WingsReader);
     }
 
     /**
@@ -179,10 +189,11 @@ public static  T object(byte[] json, @NotNull Type targetType) {
     /**
      * Deserialization with the wings convention
      */
-    @Contract("!null,_->!null")
-    public static  T object(byte[] json, @NotNull Class targetType) {
+    @Contract("!null,_,_->!null")
+    public static  T object(byte[] json, @NotNull Class targetType, Class... generics) {
         if (json == null) return null;
-        return JSON.parseObject(json, targetType, WingsReader);
+        Type genericType = TypeSugar.type(targetType, generics);
+        return JSON.parseObject(json, genericType, WingsReader);
     }
 
     /**
@@ -211,6 +222,78 @@ public static byte[] bytes(Object obj) {
         return JSON.toJSONBytes(obj, WingsWriter);
     }
 
+    //// path
+
+    private static final ConcurrentHashMap JsonPathCache = new ConcurrentHashMap<>();
+
+    /**
+     * weak cached JsonPath
+     */
+    public static JSONPath path(@NotNull String path) {
+        return path(path, null, WingsPath);
+    }
+
+    /**
+     * weak cached JsonPath
+     */
+    public static JSONPath path(@NotNull String path, Type type) {
+        return path(path, type, WingsPath);
+    }
+
+    /**
+     * weak cached JsonPath
+     */
+    public static JSONPath path(@NotNull String path, Class type, Class... generics) {
+        Type genericType = TypeSugar.type(type, generics);
+        return path(path, genericType, WingsPath);
+    }
+
+    /**
+     * weak cached JsonPath
+     */
+    public static JSONPath path(@NotNull String path, Type type, JSONPath.Feature... features) {
+        ArrayKey key = new ArrayKey(path, type, features);
+        return JsonPathCache.computeIfAbsent(key, ignore -> JSONPath.of(path, type, features));
+    }
+
+    /**
+     * cached JsonPath
+     */
+    public static JSONPath path(@NotNull String[] paths, Type[] types, JSONPath.Feature... features) {
+        return path(paths, types, features, WingsReader);
+    }
+
+    /**
+     * cached JsonPath
+     */
+    public static JSONPath path(@NotNull String[] paths, Type[] types, JSONPath.Feature[] pathFeatures, JSONReader.Feature... features) {
+        ArrayKey key = new ArrayKey(paths, types, pathFeatures, features);
+        long[] pfs = features(paths.length, pathFeatures);
+        return JsonPathCache.computeIfAbsent(key, ignore -> JSONPath.of(paths, types, null, pfs, null, features));
+    }
+
+    public static long[] features(int size, JSONPath.Feature... features) {
+        if (size <= 0) return null;
+        long mask = featureMask(features);
+        return features(size, mask);
+    }
+
+    public static long featureMask(JSONPath.Feature... features) {
+        if (features == null || features.length == 0) return WingsPathMask;
+
+        long ft = 0;
+        for (JSONPath.Feature f : features) {
+            ft = ft | f.mask;
+        }
+        return ft;
+    }
+
+    private static long @Nullable [] features(int size, long features) {
+        long[] pts = new long[size];
+        Arrays.fill(pts, features);
+        return pts;
+    }
+
     ////
 
     @Contract("_,_,!null->!null")
diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java
index 7d97e0cb..b226579a 100644
--- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java
+++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java
@@ -1,19 +1,22 @@
 package pro.fessional.wings.slardar.jackson;
 
-import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.cfg.MapperBuilder;
 import com.fasterxml.jackson.databind.json.JsonMapper;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import lombok.SneakyThrows;
 import org.jetbrains.annotations.Contract;
 import org.jetbrains.annotations.NotNull;
+import org.springframework.core.ResolvableType;
+import org.springframework.core.convert.TypeDescriptor;
 import pro.fessional.mirana.text.WhiteUtil;
 import pro.fessional.mirana.time.DateFormatter;
 import pro.fessional.wings.silencer.datetime.DateTimePattern;
+import pro.fessional.wings.silencer.enhance.TypeSugar;
 import pro.fessional.wings.slardar.autozone.AutoZoneType;
 import pro.fessional.wings.slardar.autozone.json.JacksonLocalDateTimeDeserializer;
 import pro.fessional.wings.slardar.autozone.json.JacksonLocalDateTimeSerializer;
@@ -22,6 +25,7 @@
 import pro.fessional.wings.slardar.autozone.json.JacksonZonedDateTimeDeserializer;
 import pro.fessional.wings.slardar.autozone.json.JacksonZonedDateTimeSerializer;
 
+import java.lang.reflect.Type;
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
 import java.time.ZonedDateTime;
@@ -153,6 +157,7 @@ public enum Style {
     // https://github.com/FasterXML/jackson-modules-java8/tree/master/datetime#usage
     public static final ObjectMapper JsonPlain = buildPlain(JsonMapper.builder().findAndAddModules()).build();
     public static final XmlMapper XmlPlain = buildPlain(XmlMapper.builder().findAndAddModules()).build();
+    public static final TypeFactory TypeFactoryPlain = JsonPlain.getTypeFactory();
 
     //// wings autoZone ser/des
     protected static JacksonLocalDateTimeSerializer beanLocalDateTimeSerializer;
@@ -337,14 +342,39 @@ public static boolean asXml(byte[] str) {
         return false;
     }
 
+    /////////////
+
+    /**
+     * construct jackson's JavaType by TypeSugar
+     */
+    public static JavaType javaType(@NotNull Class targetType, Class... generics) {
+        Type type = TypeSugar.type(targetType, generics);
+        return TypeFactoryPlain.constructType(type);
+    }
+
+    /**
+     * construct jackson's JavaType in spring way
+     */
+    public static JavaType javaType(@NotNull TypeDescriptor targetType) {
+        Type type = targetType.getResolvableType().getType();
+        return TypeFactoryPlain.constructType(type);
+    }
+
+    /**
+     * construct jackson's JavaType in spring way
+     */
+    public static JavaType javaType(@NotNull ResolvableType targetType) {
+        return TypeFactoryPlain.constructType(targetType.getType());
+    }
+
     /**
      * wings style read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_->!null")
-    public static  T object(String text, @NotNull Class targetType) {
+    @Contract("!null,_,_->!null")
+    public static  T object(String text, @NotNull Class targetType, Class... generics) {
         if (text == null) return null;
-        return MapperWings(!asXml(text)).readValue(text, targetType);
+        return MapperWings(!asXml(text)).readValue(text, javaType(targetType, generics));
     }
 
 
@@ -352,10 +382,10 @@ public static  T object(String text, @NotNull Class targetType) {
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static  T object(String text, @NotNull Class targetType, @NotNull Style style) {
+    @Contract("_,!null,_,_ -> !null")
+    public static  T object(@NotNull Style style, String text, @NotNull Class targetType, Class... generics) {
         if (text == null) return null;
-        return Mapper(style, !asXml(text)).readValue(text, targetType);
+        return Mapper(style, !asXml(text)).readValue(text, javaType(targetType, generics));
     }
 
     /**
@@ -372,32 +402,55 @@ public static  T object(String text, @NotNull JavaType targetType) {
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static  T object(String text, @NotNull JavaType targetType, @NotNull Style style) {
+    @Contract("_,!null,_ -> !null")
+    public static  T object(@NotNull Style style, String text, @NotNull JavaType targetType) {
         if (text == null) return null;
         return Mapper(style, !asXml(text)).readValue(text, targetType);
     }
 
+
     /**
      * wings style read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
     @Contract("!null,_->!null")
-    public static  T object(String text, @NotNull TypeReference targetType) {
+    public static  T object(String text, @NotNull ResolvableType targetType) {
         if (text == null) return null;
-        return MapperWings(!asXml(text)).readValue(text, targetType);
+        return MapperWings(!asXml(text)).readValue(text, javaType(targetType));
     }
 
     /**
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static  T object(String text, @NotNull TypeReference targetType, @NotNull Style style) {
+    @Contract("_,!null,_ -> !null")
+    public static  T object(@NotNull Style style, String text, @NotNull ResolvableType targetType) {
         if (text == null) return null;
-        return Mapper(style, !asXml(text)).readValue(text, targetType);
+        return Mapper(style, !asXml(text)).readValue(text, javaType(targetType));
     }
 
+
+    /**
+     * wings style read text to object, if text asXml, read as xml, otherwise as json
+     */
+    @SneakyThrows
+    @Contract("!null,_->!null")
+    public static  T object(String text, @NotNull TypeDescriptor targetType) {
+        if (text == null) return null;
+        return MapperWings(!asXml(text)).readValue(text, javaType(targetType));
+    }
+
+    /**
+     * Auto read text to object, if text asXml, read as xml, otherwise as json
+     */
+    @SneakyThrows
+    @Contract("_,!null,_ -> !null")
+    public static  T object(@NotNull Style style, String text, @NotNull TypeDescriptor targetType) {
+        if (text == null) return null;
+        return Mapper(style, !asXml(text)).readValue(text, javaType(targetType));
+    }
+
+
     /**
      * wings style read text to object, if text asXml, read as xml, otherwise as json
      */
@@ -412,10 +465,10 @@ public static JsonNode object(String text) {
      * wings style read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_->!null")
-    public static  T object(byte[] text, @NotNull Class targetType) {
+    @Contract("!null,_,_->!null")
+    public static  T object(byte[] text, @NotNull Class targetType, Class... generics) {
         if (text == null) return null;
-        return MapperWings(!asXml(text)).readValue(text, targetType);
+        return MapperWings(!asXml(text)).readValue(text, javaType(targetType, generics));
     }
 
 
@@ -423,10 +476,10 @@ public static  T object(byte[] text, @NotNull Class targetType) {
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static  T object(byte[] text, @NotNull Class targetType, @NotNull Style style) {
+    @Contract("_,!null,_,_ -> !null")
+    public static  T object(@NotNull Style style, byte[] text, @NotNull Class targetType, Class... generics) {
         if (text == null) return null;
-        return Mapper(style, !asXml(text)).readValue(text, targetType);
+        return Mapper(style, !asXml(text)).readValue(text, javaType(targetType, generics));
     }
 
     /**
@@ -443,8 +496,8 @@ public static  T object(byte[] text, @NotNull JavaType targetType) {
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static  T object(byte[] text, @NotNull JavaType targetType, @NotNull Style style) {
+    @Contract("_, !null, _ -> !null")
+    public static  T object(@NotNull Style style, byte[] text, @NotNull JavaType targetType) {
         if (text == null) return null;
         return Mapper(style, !asXml(text)).readValue(text, targetType);
     }
@@ -454,19 +507,39 @@ public static  T object(byte[] text, @NotNull JavaType targetType, @NotNull S
      */
     @SneakyThrows
     @Contract("!null,_->!null")
-    public static  T object(byte[] text, @NotNull TypeReference targetType) {
+    public static  T object(byte[] text, @NotNull ResolvableType targetType) {
         if (text == null) return null;
-        return MapperWings(!asXml(text)).readValue(text, targetType);
+        return MapperWings(!asXml(text)).readValue(text, javaType(targetType));
     }
 
     /**
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static  T object(byte[] text, @NotNull TypeReference targetType, @NotNull Style style) {
+    @Contract("_, !null, _ -> !null")
+    public static  T object(@NotNull Style style, byte[] text, @NotNull ResolvableType targetType) {
         if (text == null) return null;
-        return Mapper(style, !asXml(text)).readValue(text, targetType);
+        return Mapper(style, !asXml(text)).readValue(text, javaType(targetType));
+    }
+
+    /**
+     * wings style read text to object, if text asXml, read as xml, otherwise as json
+     */
+    @SneakyThrows
+    @Contract("!null,_->!null")
+    public static  T object(byte[] text, @NotNull TypeDescriptor targetType) {
+        if (text == null) return null;
+        return MapperWings(!asXml(text)).readValue(text, javaType(targetType));
+    }
+
+    /**
+     * Auto read text to object, if text asXml, read as xml, otherwise as json
+     */
+    @SneakyThrows
+    @Contract("_, !null, _ -> !null")
+    public static  T object(@NotNull Style style, byte[] text, @NotNull TypeDescriptor targetType) {
+        if (text == null) return null;
+        return Mapper(style, !asXml(text)).readValue(text, javaType(targetType));
     }
 
     /**
@@ -483,8 +556,8 @@ public static JsonNode object(byte[] text) {
      * Auto read text to object, if text asXml, read as xml, otherwise as json
      */
     @SneakyThrows
-    @Contract("!null,_->!null")
-    public static JsonNode object(byte[] text, @NotNull Style style) {
+    @Contract("_, !null -> !null")
+    public static JsonNode object(@NotNull Style style, byte[] text) {
         if (text == null) return null;
         return Mapper(style, !asXml(text)).readTree(text);
     }
@@ -502,8 +575,8 @@ public static String string(Object obj) {
      * serialization to json
      */
     @SneakyThrows
-    @Contract("!null,_->!null")
-    public static String string(Object obj, @NotNull Style style) {
+    @Contract("_, !null -> !null")
+    public static String string(@NotNull Style style, Object obj) {
         return obj == null ? null : Mapper(style, true).writeValueAsString(obj);
     }
 
@@ -520,8 +593,8 @@ public static String string(Object obj, boolean json) {
      * serialization to json/xml
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static String string(Object obj, @NotNull Style style, boolean json) {
+    @Contract("_, !null, _ -> !null")
+    public static String string(@NotNull Style style, Object obj, boolean json) {
         return obj == null ? null : Mapper(style, json).writeValueAsString(obj);
     }
 
@@ -538,8 +611,8 @@ public static byte[] bytes(Object obj) {
      * serialization to json
      */
     @SneakyThrows
-    @Contract("!null,_->!null")
-    public static byte[] bytes(Object obj, @NotNull Style style) {
+    @Contract("_, !null -> !null")
+    public static byte[] bytes(@NotNull Style style, Object obj) {
         return obj == null ? null : Mapper(style, true).writeValueAsBytes(obj);
     }
 
@@ -556,8 +629,8 @@ public static byte[] bytes(Object obj, boolean json) {
      * serialization to json/xml
      */
     @SneakyThrows
-    @Contract("!null,_,_->!null")
-    public static byte[] bytes(Object obj, @NotNull Style style, boolean json) {
+    @Contract("_, !null, _ -> !null")
+    public static byte[] bytes(@NotNull Style style, Object obj, boolean json) {
         return obj == null ? null : Mapper(style, json).writeValueAsBytes(obj);
     }
 
diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java
index 016d8a5d..4d751940 100644
--- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java
+++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java
@@ -1,6 +1,8 @@
 package pro.fessional.wings.slardar.fastjson;
 
 import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.JSONPath;
 import com.alibaba.fastjson2.JSONWriter.Feature;
 import com.alibaba.fastjson2.annotation.JSONField;
 import io.qameta.allure.TmsLink;
@@ -8,6 +10,7 @@
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import pro.fessional.mirana.data.R;
 import pro.fessional.mirana.time.ThreadNow;
 import pro.fessional.wings.testing.silencer.data.BoxingArray;
 import pro.fessional.wings.testing.silencer.data.BoxingValue;
@@ -21,6 +24,8 @@
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
 import java.time.ZonedDateTime;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * register_custom_reader_writer_cn
@@ -59,7 +64,7 @@ public void testDefault() {
         testDefault(new TransientPojo().defaults());
     }
 
-    private  void testDefault(T t1){
+    private  void testDefault(T t1) {
         final String s0 = JSON.toJSONString(t1);
         Class clz = t1.getClass();
         log.info("testDefault, class={}, json={}", clz.getSimpleName(), s0);
@@ -77,7 +82,7 @@ public void testString() {
         final Dto d1 = JSON.parseObject(s0, Dto.class);
         Assertions.assertEquals(d0, d1);
     }
-    
+
     /**
      * WriteNonStringValueAsString format Number
      */
@@ -106,4 +111,29 @@ public void testSingle() {
         Assertions.assertEquals("\"3.14\"", JSON.toJSONString(new BigDecimal("3.14"), Feature.WriteNonStringValueAsString));
     }
 
+    @Test
+    @TmsLink("C13126")
+    public void testJsonPath() {
+        CollectionValue data = new CollectionValue().defaults();
+        R r = R.ok("You're fired", data);
+        String json = FastJsonHelper.string(r);
+        JSONObject obj = FastJsonHelper.object(json);
+
+        JSONPath p1 = FastJsonHelper.path("$.success");
+        JSONPath p2 = FastJsonHelper.path("$.success");
+        Assertions.assertSame(p1, p2);
+        Assertions.assertEquals(true, p1.eval(obj));
+
+        JSONPath pn = FastJsonHelper.path("$.notfound");
+        Assertions.assertNull(pn.eval(obj));
+
+        JSONPath pd = FastJsonHelper.path("$.data.emptyList");
+        Assertions.assertEquals(Collections.emptyList(), pd.eval(obj));
+
+        JSONPath pl1 = FastJsonHelper.path("$.data.longList", List.class, Long.class);
+        Assertions.assertEquals(CollectionValue.LongList, pl1.extract(json));
+
+        JSONPath pl2 = FastJsonHelper.path("$.data.longList", List.class, Long.class);
+        Assertions.assertEquals(CollectionValue.LongList, pl2.extract(json));
+    }
 }
diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/JsonConversionTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/JsonConversionTest.java
index 75dccc06..9d18154a 100644
--- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/JsonConversionTest.java
+++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/JsonConversionTest.java
@@ -1,6 +1,5 @@
 package pro.fessional.wings.slardar.json;
 
-import com.alibaba.fastjson2.TypeReference;
 import io.qameta.allure.TmsLink;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
@@ -12,7 +11,6 @@
 import pro.fessional.wings.slardar.fastjson.FastJsonHelper;
 import pro.fessional.wings.slardar.serialize.JsonConversion;
 
-import java.lang.reflect.Type;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.time.ZonedDateTime;
@@ -98,8 +96,7 @@ void fastjsonGenerics() {
         R rd = R.okData(dto);
         String rd0 = FastJsonHelper.string(rd);
         //
-        Type rdt = new TypeReference>() {}.getType();
-        R rd1 = FastJsonHelper.object(rd0, rdt);
+        R rd1 = FastJsonHelper.object(rd0, R.class, Dto.class);
         log.info("rd1={}", rd1);
         //
         final ResolvableType tat = ResolvableType.forClassWithGenerics(R.class, Dto.class);
diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java
new file mode 100644
index 00000000..188430ef
--- /dev/null
+++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java
@@ -0,0 +1,183 @@
+package pro.fessional.wings.slardar.json;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import io.qameta.allure.TmsLink;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.core.ResolvableType;
+import org.springframework.core.convert.TypeDescriptor;
+import pro.fessional.wings.silencer.enhance.TypeSugar;
+
+import java.lang.reflect.Type;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author trydofor
+ * @since 2024-06-09
+ */
+@Slf4j
+public class TypeReferenceTest {
+
+    @Test
+    @TmsLink("C13127")
+    public void testType() {
+        {
+            Type fastRef = new com.alibaba.fastjson2.TypeReference>>() {}.getType();
+            Type jackRef = new com.fasterxml.jackson.core.type.TypeReference>>() {}.getType();
+
+            Type descType = TypeDescriptor.map(Map.class,
+                TypeDescriptor.valueOf(String.class),
+                TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))
+            ).getResolvableType().getType();
+
+            Type resoType = ResolvableType.forClassWithGenerics(Map.class,
+                ResolvableType.forClass(String.class),
+                ResolvableType.forClassWithGenerics(List.class, Long[].class)
+            ).getType();
+
+            Type helpType = TypeSugar.resolve(Map.class, String.class, List.class, Long[].class).getType();
+
+
+            log.info("fastRef={}", fastRef);
+            log.info("jackRef={}", jackRef);
+            log.info("descType={}", descType);
+            log.info("resoType={}", resoType);
+            log.info("helpType={}", helpType);
+
+            Assertions.assertEquals(fastRef, jackRef);
+            Assertions.assertEquals(fastRef, descType);
+            Assertions.assertEquals(fastRef, resoType);
+            Assertions.assertEquals(fastRef, helpType);
+
+            // check cache
+            Type fastRef1 = new com.alibaba.fastjson2.TypeReference>>() {}.getType();
+            Type jackRef1 = new com.fasterxml.jackson.core.type.TypeReference>>() {}.getType();
+
+            Type descType1 = TypeDescriptor.map(Map.class,
+                TypeDescriptor.valueOf(String.class),
+                TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))
+            ).getResolvableType().getType();
+
+            Type resoType1 = ResolvableType.forClassWithGenerics(Map.class,
+                ResolvableType.forClass(String.class),
+                ResolvableType.forClassWithGenerics(List.class, Long[].class)
+            ).getType();
+
+            Type helpType1 = TypeSugar.resolve(Map.class, String.class, List.class, Long[].class).getType();
+
+            Assertions.assertNotSame(fastRef, fastRef1);
+            Assertions.assertNotSame(jackRef, jackRef1);
+            Assertions.assertNotSame(descType, descType1);
+            Assertions.assertNotSame(resoType, resoType1);
+            Assertions.assertSame(helpType, helpType1);
+        }
+        {
+            Type fastRef = new com.alibaba.fastjson2.TypeReference, String>>() {}.getType();
+            Type jackRef = new com.fasterxml.jackson.core.type.TypeReference, String>>() {}.getType();
+
+            Type descType = TypeDescriptor.map(Map.class,
+                TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)),
+                TypeDescriptor.valueOf(String.class)
+            ).getResolvableType().getType();
+
+            Type resoType = ResolvableType.forClassWithGenerics(Map.class,
+                ResolvableType.forClassWithGenerics(List.class, Long[].class),
+                ResolvableType.forClass(String.class)
+            ).getType();
+
+            Type helpType = TypeSugar.resolve(Map.class, List.class, Long[].class, String.class).getType();
+
+            log.info("fastRef={}", fastRef);
+            log.info("jackRef={}", jackRef);
+            log.info("descType={}", descType);
+            log.info("resoType={}", resoType);
+            log.info("helpType={}", helpType);
+
+            Assertions.assertEquals(fastRef, jackRef);
+            Assertions.assertEquals(fastRef, descType);
+            Assertions.assertEquals(fastRef, resoType);
+            Assertions.assertEquals(fastRef, helpType);
+        }
+        {
+            Type fastRef = new com.alibaba.fastjson2.TypeReference>, String>>() {}.getType();
+            Type jackRef = new com.fasterxml.jackson.core.type.TypeReference>, String>>() {}.getType();
+
+            Type descType = TypeDescriptor.map(Map.class,
+                TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))),
+                TypeDescriptor.valueOf(String.class)
+            ).getResolvableType().getType();
+
+            Type resoType = ResolvableType.forClassWithGenerics(Map.class,
+                ResolvableType.forClassWithGenerics(List.class, ResolvableType.forClassWithGenerics(List.class, Long[].class)),
+                ResolvableType.forClass(String.class)
+            ).getType();
+
+            Type helpType = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class).getType();
+
+            log.info("fastRef={}", fastRef);
+            log.info("jackRef={}", jackRef);
+            log.info("descType={}", descType);
+            log.info("resoType={}", resoType);
+            log.info("resoType={}", helpType);
+
+            Assertions.assertEquals(fastRef, jackRef);
+            Assertions.assertEquals(fastRef, descType);
+            Assertions.assertEquals(fastRef, resoType);
+            Assertions.assertEquals(fastRef, helpType);
+        }
+        {
+            Type fastRef = new com.alibaba.fastjson2.TypeReference>, List>>() {}.getType();
+            Type jackRef = new com.fasterxml.jackson.core.type.TypeReference>, List>>() {}.getType();
+
+            Type descType = TypeDescriptor.map(Map.class,
+                TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class))),
+                TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class))
+            ).getResolvableType().getType();
+
+            Type resoType = ResolvableType.forClassWithGenerics(Map.class,
+                ResolvableType.forClassWithGenerics(List.class, ResolvableType.forClassWithGenerics(List.class, Long[].class)),
+                ResolvableType.forClassWithGenerics(List.class, ResolvableType.forClass(String.class))
+            ).getType();
+
+            Type helpType = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, List.class, String.class).getType();
+
+            log.info("fastRef={}", fastRef);
+            log.info("jackRef={}", jackRef);
+            log.info("descType={}", descType);
+            log.info("resoType={}", resoType);
+            log.info("resoType={}", helpType);
+
+            Assertions.assertEquals(fastRef, jackRef);
+            Assertions.assertEquals(fastRef, descType);
+            Assertions.assertEquals(fastRef, resoType);
+            Assertions.assertEquals(fastRef, helpType);
+        }
+
+        // java type
+        {
+            TypeFactory tf = new ObjectMapper().getTypeFactory();
+            Type jackRef = new com.fasterxml.jackson.core.type.TypeReference>, String>>() {}.getType();
+            JavaType jt0 = tf.constructType(jackRef);
+            JavaType jt1 = tf.constructType(TypeSugar.type(Map.class, List.class, List.class, Long[].class, String.class));
+            Assertions.assertEquals(jt0, jt1);
+
+
+            Type tp0 = new com.google.common.reflect.TypeToken>(){}.getType();
+            Type tp1 = new com.alibaba.fastjson2.TypeReference>() {}.getType();
+            Type tp2 = new com.fasterxml.jackson.core.type.TypeReference>() {}.getType();
+            Type tp3 = ResolvableType.forClassWithGenerics(List.class, String.class).getType();
+            Type tp4 = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)).getResolvableType().getType();
+            Type tp5 = TypeSugar.type(List.class, String.class);
+
+            Assertions.assertEquals(tp0, tp1);
+            Assertions.assertEquals(tp0, tp2);
+            Assertions.assertEquals(tp0, tp3);
+            Assertions.assertEquals(tp0, tp4);
+            Assertions.assertEquals(tp0, tp5);
+        }
+    }
+}
diff --git a/wings/testing-silencer/src/main/java/pro/fessional/wings/testing/silencer/data/CollectionValue.java b/wings/testing-silencer/src/main/java/pro/fessional/wings/testing/silencer/data/CollectionValue.java
index 2d68b897..4e1c78cd 100644
--- a/wings/testing-silencer/src/main/java/pro/fessional/wings/testing/silencer/data/CollectionValue.java
+++ b/wings/testing-silencer/src/main/java/pro/fessional/wings/testing/silencer/data/CollectionValue.java
@@ -22,57 +22,57 @@ public class CollectionValue implements DefaultData {
 
     public static final List EmptyList = new ArrayList<>();
     public static final Set EmptySet = new HashSet<>();
-    public static final Map EmptyMap = new HashMap<>();
+    public static final Map EmptyMap = new HashMap<>();
 
     public static final List BoolList = new ArrayList<>();
     public static final Set BoolSet = new HashSet<>();
-    public static final Map BoolMap = new HashMap<>();
+    public static final Map BoolMap = new HashMap<>();
 
     public static final List LongList = new ArrayList<>();
     public static final Set LongSet = new HashSet<>();
-    public static final Map LongMap = new HashMap<>();
+    public static final Map LongMap = new HashMap<>();
 
     public static final List DoubleList = new ArrayList<>();
     public static final Set DoubleSet = new HashSet<>();
-    public static final Map DoubleMap = new HashMap<>();
+    public static final Map DoubleMap = new HashMap<>();
 
     static {
         for (int i = 0; i < BoolArrValue.length; i++) {
             BoolList.add(BoolArrValue[i]);
             BoolSet.add(BoolArrValue[i]);
-            BoolMap.put(i, BoolArrValue[i]);
+            BoolMap.put("k" + i, BoolArrValue[i]);
         }
         for (int i = 0; i < LongArrValue.length; i++) {
             LongList.add(LongArrValue[i]);
             LongSet.add(LongArrValue[i]);
-            LongMap.put(i, LongArrValue[i]);
+            LongMap.put("k" + i, LongArrValue[i]);
         }
         for (int i = 0; i < DoubleArrValue.length; i++) {
             DoubleList.add(DoubleArrValue[i]);
             DoubleSet.add(DoubleArrValue[i]);
-            DoubleMap.put(i, DoubleArrValue[i]);
+            DoubleMap.put("k" + i, DoubleArrValue[i]);
         }
     }
 
     private List nullList = null;
     private Set nullSet = null;
-    private Map nullMap = null;
+    private Map nullMap = null;
 
     private List emptyList = null;
     private Set emptySet = null;
-    private Map emptyMap = null;
+    private Map emptyMap = null;
 
     private List boolList = null;
     private Set boolSet = null;
-    private Map boolMap = null;
+    private Map boolMap = null;
 
     private List longList = null;
     private Set longSet = null;
-    private Map longMap = null;
+    private Map longMap = null;
 
     private List doubleList = null;
     private Set doubleSet = null;
-    private Map doubleMap = null;
+    private Map doubleMap = null;
 
     @Override
     public CollectionValue defaults() {
diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java
index 1519beb0..0eb40dae 100644
--- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java
+++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java
@@ -1,6 +1,5 @@
 package pro.fessional.wings.warlock.security.justauth;
 
-import com.alibaba.fastjson2.TypeReference;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
@@ -12,6 +11,7 @@
 import pro.fessional.mirana.code.RandCode;
 import pro.fessional.mirana.data.Null;
 import pro.fessional.mirana.text.FormatUtil;
+import pro.fessional.wings.silencer.enhance.TypeSugar;
 import pro.fessional.wings.slardar.fastjson.FastJsonHelper;
 import pro.fessional.wings.slardar.security.WingsAuthHelper;
 import pro.fessional.wings.slardar.servlet.request.RequestHelper;
@@ -38,7 +38,7 @@ public class AuthStateBuilder {
     public static final String ParamState = "state";
     public static final String KeyStateArr = "s";
     public static final String KeyAuthZone = "z";
-    public static final Type ParamType = new TypeReference>() {}.getType();
+    public static final Type ParamType = TypeSugar.type(Map.class, String.class, String[].class);
 
     @Setter
     private Aes aes = Aes256.of(RandCode.strong(RAND_LEN));
diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/MemLoginTest.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/MemLoginTest.java
index 9c81d66b..e357eb74 100644
--- a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/MemLoginTest.java
+++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/MemLoginTest.java
@@ -1,6 +1,5 @@
 package pro.fessional.wings.warlock.security;
 
-import com.alibaba.fastjson2.TypeReference;
 import io.qameta.allure.TmsLink;
 import lombok.Setter;
 import lombok.extern.slf4j.Slf4j;
@@ -61,9 +60,8 @@ public void testUsernameLogin() {
         String au4 = OkHttpClientHelper.extractString(r4, false);
         log.info("UsernameLogin auth4={}", au4);
 
-        final TypeReference> setRef = new TypeReference<>() {};
-        final Set st3 = FastJsonHelper.object(au3, setRef);
-        final Set st4 = FastJsonHelper.object(au4, setRef);
+        final Set st3 = FastJsonHelper.object(au3, Set.class, String.class);
+        final Set st4 = FastJsonHelper.object(au4, Set.class, String.class);
         Assertions.assertEquals(st3, st4);
 
         List exp = Arrays.asList("ROLE_SYSTEM", "ROLE_ADMIN", "user-perm");
@@ -110,8 +108,8 @@ public void testEmailLogin() {
         String au4 = OkHttpClientHelper.extractString(r4, false);
         log.info("EmailLogin auth4={}", au4);
 
-        final Set st3 = FastJsonHelper.object(au3, new TypeReference>() {});
-        final Set st4 = FastJsonHelper.object(au4, new TypeReference>() {});
+        final Set st3 = FastJsonHelper.object(au3, Set.class, String.class);
+        final Set st4 = FastJsonHelper.object(au4,Set.class, String.class);
         Assertions.assertEquals(st3, st4);
 
         Assertions.assertTrue(st3.contains("email-perm"));
diff --git a/wings/warlock/src/test/java/pro/fessional/wings/warlock/other/ResultSerializeTest.java b/wings/warlock/src/test/java/pro/fessional/wings/warlock/other/ResultSerializeTest.java
index c766ce75..461f9d52 100644
--- a/wings/warlock/src/test/java/pro/fessional/wings/warlock/other/ResultSerializeTest.java
+++ b/wings/warlock/src/test/java/pro/fessional/wings/warlock/other/ResultSerializeTest.java
@@ -38,7 +38,7 @@ public void testZoneid() {
         log.info("{}", t2);
     }
 
-    @SuppressWarnings("Convert2Diamond")
+    @SuppressWarnings("all")
     @SneakyThrows
     @Test
     @TmsLink("C14003")
@@ -61,7 +61,7 @@ public void testJackson() {
         ObjectMapper om = new ObjectMapper();
         final String json = om.writeValueAsString(r1);
         log.info("testJackson={}", json);
-        final R r2 = om.readValue(json, new com.fasterxml.jackson.core.type.TypeReference>() {});
+        final R r2 = om.readValue(json, R.class);
         Assertions.assertEquals(r1, r2);
         Assertions.assertNull(r2.getCause());
         Assertions.assertNull(r2.getI18nArgs());
@@ -81,7 +81,7 @@ public void testFastjson() {
                 .setI18nMessage("i18nCode", "1");
         final String json = FastJsonHelper.string(r1);
         log.info(json);
-        final R r2 = FastJsonHelper.object(json, new com.alibaba.fastjson2.TypeReference>() {});
+        final R r2 = FastJsonHelper.object(json, R.class);
         Assertions.assertEquals(r1, r2);
         Assertions.assertNull(r2.getCause());
         Assertions.assertNull(r2.getI18nArgs());