From 2b6ecfcf1ee8d1c646f278b4c3b429adee1463be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=89=91=E5=99=A8=E8=BF=91?= Date: Thu, 1 Jul 2021 16:04:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=B7=A5=E5=85=B7=E7=B1=BBTo?= =?UTF-8?q?StringBuilder=EF=BC=8C=E6=8A=BD=E8=B1=A1Cache=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../protostar/schema/CollectionSchema.java | 20 +-- .../protostar/schema/ConvertSchema.java | 30 ++-- .../protostar/schema/ObjectSchema.java | 21 +-- .../protostar/schema/StringSchema.java | 22 +-- .../github/yezhihao/protostar/util/Cache.java | 43 ++++++ .../protostar/util/ToStringBuilder.java | 144 ++++++++++++++++++ 6 files changed, 209 insertions(+), 71 deletions(-) create mode 100644 src/main/java/io/github/yezhihao/protostar/util/Cache.java create mode 100644 src/main/java/io/github/yezhihao/protostar/util/ToStringBuilder.java diff --git a/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java b/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java index e20fc67..c99b57b 100644 --- a/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java +++ b/src/main/java/io/github/yezhihao/protostar/schema/CollectionSchema.java @@ -1,30 +1,18 @@ package io.github.yezhihao.protostar.schema; import io.github.yezhihao.protostar.Schema; +import io.github.yezhihao.protostar.util.Cache; import io.netty.buffer.ByteBuf; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; public class CollectionSchema implements Schema> { - private static volatile Map cache = new HashMap<>(); + private static final Cache CACHE = new Cache<>(); - public static Schema getInstance(Schema schema) { - Object key = schema; - CollectionSchema instance; - if ((instance = cache.get(key)) == null) { - synchronized (cache) { - if ((instance = cache.get(key)) == null) { - instance = new CollectionSchema(schema); - cache.put(schema, instance); - log.debug("new CollectionSchema({})", schema); - } - } - } - return instance; + public static CollectionSchema getInstance(Schema schema) { + return CACHE.get(schema, key -> new CollectionSchema(key)); } private final Schema schema; diff --git a/src/main/java/io/github/yezhihao/protostar/schema/ConvertSchema.java b/src/main/java/io/github/yezhihao/protostar/schema/ConvertSchema.java index aeb4b12..9ae56c1 100644 --- a/src/main/java/io/github/yezhihao/protostar/schema/ConvertSchema.java +++ b/src/main/java/io/github/yezhihao/protostar/schema/ConvertSchema.java @@ -2,36 +2,24 @@ package io.github.yezhihao.protostar.schema; import io.github.yezhihao.protostar.Schema; import io.github.yezhihao.protostar.converter.Converter; +import io.github.yezhihao.protostar.util.Cache; import io.netty.buffer.ByteBuf; -import java.util.HashMap; -import java.util.Map; - /** * 自定义结构转换 */ public class ConvertSchema implements Schema { - private static volatile Map cache = new HashMap<>(); + private static final Cache cache = new Cache<>(); - public static Schema getInstance(Class clazz) { - String key = clazz.getName(); - ConvertSchema instance; - if ((instance = cache.get(key)) == null) { - synchronized (cache) { - if ((instance = cache.get(key)) == null) { - try { - Converter converter = clazz.newInstance(); - instance = new ConvertSchema(converter); - cache.put(key, instance); - log.debug("new ConvertSchema({})", clazz); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + public static ConvertSchema getInstance(Class clazz) { + return cache.get(clazz.getName(), key -> { + try { + return new ConvertSchema(clazz.newInstance()); + } catch (Exception e) { + throw new RuntimeException(e); } - } - return instance; + }); } private final Converter converter; diff --git a/src/main/java/io/github/yezhihao/protostar/schema/ObjectSchema.java b/src/main/java/io/github/yezhihao/protostar/schema/ObjectSchema.java index 599469d..d29e820 100644 --- a/src/main/java/io/github/yezhihao/protostar/schema/ObjectSchema.java +++ b/src/main/java/io/github/yezhihao/protostar/schema/ObjectSchema.java @@ -1,28 +1,15 @@ package io.github.yezhihao.protostar.schema; import io.github.yezhihao.protostar.Schema; +import io.github.yezhihao.protostar.util.Cache; import io.netty.buffer.ByteBuf; -import java.util.HashMap; -import java.util.Map; - public class ObjectSchema implements Schema { - private static volatile Map cache = new HashMap<>(); + private static final Cache cache = new Cache<>(); - public static Schema getInstance(Schema schema) { - Object key = schema; - ObjectSchema instance; - if ((instance = cache.get(key)) == null) { - synchronized (cache) { - if ((instance = cache.get(key)) == null) { - instance = new ObjectSchema(schema); - cache.put(schema, instance); - log.debug("new ObjectSchema({})", schema); - } - } - } - return instance; + public static ObjectSchema getInstance(Schema schema) { + return cache.get(schema, key -> new ObjectSchema(key)); } private final Schema schema; diff --git a/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java b/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java index 6e4a0d8..f86971f 100644 --- a/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java +++ b/src/main/java/io/github/yezhihao/protostar/schema/StringSchema.java @@ -2,32 +2,20 @@ package io.github.yezhihao.protostar.schema; import io.github.yezhihao.protostar.Schema; import io.github.yezhihao.protostar.util.Bcd; +import io.github.yezhihao.protostar.util.Cache; import io.netty.buffer.ByteBuf; import java.nio.charset.Charset; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; public class StringSchema { public static class Chars implements Schema { - private static volatile Map cache = new HashMap<>(); + private static final Cache cache = new Cache<>(); - public static Schema getInstance(byte pad, String charset) { - charset = charset.toLowerCase(); - String key = new StringBuilder(10).append((char) pad).append('/').append(charset).toString(); - Chars instance; - if ((instance = cache.get(key)) == null) { - synchronized (cache) { - if ((instance = cache.get(key)) == null) { - instance = new Chars(pad, charset); - cache.put(key, instance); - log.debug("new StringSchema({},{})", pad, charset); - } - } - } - return instance; + public static Chars getInstance(final byte pad, final String charset) { + String key = new StringBuilder(10).append((char) pad).append('/').append(charset.toLowerCase()).toString(); + return cache.get(key, k -> new Chars(pad, charset)); } private final byte pad; diff --git a/src/main/java/io/github/yezhihao/protostar/util/Cache.java b/src/main/java/io/github/yezhihao/protostar/util/Cache.java new file mode 100644 index 0000000..a99edc5 --- /dev/null +++ b/src/main/java/io/github/yezhihao/protostar/util/Cache.java @@ -0,0 +1,43 @@ +package io.github.yezhihao.protostar.util; + +import java.util.HashMap; +import java.util.function.Function; + +/** + * @author yezhihao + * home https://gitee.com/yezhihao/jt808-server + */ +public class Cache { + + private volatile HashMap cache; + + public Cache() { + this(32); + } + + public Cache(int initialCapacity) { + this.cache = new HashMap<>((int) (initialCapacity / 0.75) + 1); + } + + public V get(K key) { + return cache.get(key); + } + + public V get(K key, Function function) { + V value = cache.get(key); + if (value == null) { + synchronized (cache) { + value = cache.get(key); + if (value == null) { + cache.put(key, value = function.apply(key)); + } + } + } + return value; + } + + @Override + public String toString() { + return cache.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/yezhihao/protostar/util/ToStringBuilder.java b/src/main/java/io/github/yezhihao/protostar/util/ToStringBuilder.java new file mode 100644 index 0000000..e23affa --- /dev/null +++ b/src/main/java/io/github/yezhihao/protostar/util/ToStringBuilder.java @@ -0,0 +1,144 @@ +package io.github.yezhihao.protostar.util; + +import java.beans.Transient; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BiConsumer; + +/** + * @author yezhihao + * home https://gitee.com/yezhihao/jt808-server + */ +public class ToStringBuilder { + + private static Cache CACHE = new Cache<>(); + + public static String toString(Object object) { + return toString(null, object, true, (String[]) null); + } + + public static String toString(Object object, boolean superclass, String... ignores) { + return toString(null, object, superclass, ignores); + } + + public static String toString(StringBuilder sb, Object object, boolean superclass, String... ignores) { + Class typeClass = object.getClass(); + Builder[] builders = getBuilders(typeClass, ignores); + if (sb == null) + sb = new StringBuilder(builders.length * 10); + + String name = typeClass.getName(); + sb.append(name, name.lastIndexOf('.') + 1, name.length()); + sb.append('{'); + try { + if (superclass) { + for (Builder builder : builders) + builder.append(sb, object); + } else { + for (Builder builder : builders) + if (!builder.superclass) + builder.append(sb, object); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + sb.setCharAt(sb.length() - 1, '}'); + return sb.toString(); + } + + private static Builder[] getBuilders(Class typeClass, String... ignores) { + return CACHE.get(typeClass.getName(), s -> { + Method[] methods = typeClass.getMethods(); + ArrayList result = new ArrayList<>(methods.length); + + for (Method method : methods) { + String mName = method.getName(); + String name = getName(mName); + if ((mName.startsWith("get") || mName.startsWith("is")) && + !"class".equals(name) && + !contains(ignores, name) && + method.getParameterCount() == 0 && !method.isAnnotationPresent(Transient.class)) + result.add(new Builder(name, method, !typeClass.equals(method.getDeclaringClass()))); + } + + Builder[] temp = new Builder[result.size()]; + result.toArray(temp); + Arrays.sort(temp); + return temp; + }); + } + + private static boolean contains(Object[] array, Object obj) { + if (array == null || array.length == 0 || obj == null) + return false; + for (Object t : array) { + if (obj.equals(t)) + return true; + } + return false; + } + + private static String getName(String methodName) { + char[] name = methodName.toCharArray(); + if (name[0] == 'g') { + name[3] += 32; + return new String(name, 3, name.length - 3); + } else { + name[2] += 32; + return new String(name, 2, name.length - 2); + } + } + + private static class Builder implements Comparable { + private static final BiConsumer APPEND_OBJ = (sb, obj) -> sb.append(obj); + private static final BiConsumer APPEND_ARRAY = (sb, array) -> { + sb.append('['); + int length = Array.getLength(array); + boolean tooLong = length > 140; + length = tooLong ? 140 : length; + for (int i = 0; i < length; i++) + sb.append(Array.get(array, i)).append(','); + if (tooLong) + sb.append("......"); + sb.setCharAt(sb.length() - 1, ']'); + }; + + public final String name; + public final boolean superclass; + private final Method method; + private final BiConsumer append; + + public void append(StringBuilder sb, Object obj) throws Exception { + Object value = method.invoke(obj); + if (value != null) { + sb.append(name).append('='); + append.accept(sb, value); + sb.append(','); + } + } + + public Builder(String name, Method method, boolean superclass) { + this.name = name; + this.method = method; + this.superclass = superclass; + if (method.getReturnType().isArray()) { + append = APPEND_ARRAY; + } else { + append = APPEND_OBJ; + } + } + + @Override + public int compareTo(Builder that) { + Class thatType = that.method.getReturnType(); + if (Iterable.class.isAssignableFrom(thatType) || thatType.isArray()) + return -1; + Class thisType = this.method.getReturnType(); + if (Iterable.class.isAssignableFrom(thisType) || thisType.isArray()) + return 1; + return 0; + } + } +} \ No newline at end of file