新增工具类ToStringBuilder,抽象Cache类
parent
c305df04b9
commit
2b6ecfcf1e
|
@ -1,30 +1,18 @@
|
||||||
package io.github.yezhihao.protostar.schema;
|
package io.github.yezhihao.protostar.schema;
|
||||||
|
|
||||||
import io.github.yezhihao.protostar.Schema;
|
import io.github.yezhihao.protostar.Schema;
|
||||||
|
import io.github.yezhihao.protostar.util.Cache;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class CollectionSchema<T> implements Schema<List<T>> {
|
public class CollectionSchema<T> implements Schema<List<T>> {
|
||||||
|
|
||||||
private static volatile Map<Object, CollectionSchema> cache = new HashMap<>();
|
private static final Cache<Schema, CollectionSchema> CACHE = new Cache<>();
|
||||||
|
|
||||||
public static Schema<List> getInstance(Schema schema) {
|
public static CollectionSchema getInstance(Schema schema) {
|
||||||
Object key = schema;
|
return CACHE.get(schema, key -> new CollectionSchema(key));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Schema<T> schema;
|
private final Schema<T> schema;
|
||||||
|
|
|
@ -2,36 +2,24 @@ package io.github.yezhihao.protostar.schema;
|
||||||
|
|
||||||
import io.github.yezhihao.protostar.Schema;
|
import io.github.yezhihao.protostar.Schema;
|
||||||
import io.github.yezhihao.protostar.converter.Converter;
|
import io.github.yezhihao.protostar.converter.Converter;
|
||||||
|
import io.github.yezhihao.protostar.util.Cache;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义结构转换
|
* 自定义结构转换
|
||||||
*/
|
*/
|
||||||
public class ConvertSchema<T> implements Schema<T> {
|
public class ConvertSchema<T> implements Schema<T> {
|
||||||
|
|
||||||
private static volatile Map<Object, ConvertSchema> cache = new HashMap<>();
|
private static final Cache<String, ConvertSchema> cache = new Cache<>();
|
||||||
|
|
||||||
public static Schema getInstance(Class<? extends Converter> clazz) {
|
public static ConvertSchema getInstance(Class<? extends Converter> clazz) {
|
||||||
String key = clazz.getName();
|
return cache.get(clazz.getName(), key -> {
|
||||||
ConvertSchema instance;
|
|
||||||
if ((instance = cache.get(key)) == null) {
|
|
||||||
synchronized (cache) {
|
|
||||||
if ((instance = cache.get(key)) == null) {
|
|
||||||
try {
|
try {
|
||||||
Converter converter = clazz.newInstance();
|
return new ConvertSchema(clazz.newInstance());
|
||||||
instance = new ConvertSchema(converter);
|
|
||||||
cache.put(key, instance);
|
|
||||||
log.debug("new ConvertSchema({})", clazz);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Converter<T> converter;
|
private final Converter<T> converter;
|
||||||
|
|
|
@ -1,28 +1,15 @@
|
||||||
package io.github.yezhihao.protostar.schema;
|
package io.github.yezhihao.protostar.schema;
|
||||||
|
|
||||||
import io.github.yezhihao.protostar.Schema;
|
import io.github.yezhihao.protostar.Schema;
|
||||||
|
import io.github.yezhihao.protostar.util.Cache;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class ObjectSchema<T> implements Schema<T> {
|
public class ObjectSchema<T> implements Schema<T> {
|
||||||
|
|
||||||
private static volatile Map<Object, ObjectSchema> cache = new HashMap<>();
|
private static final Cache<Schema, ObjectSchema> cache = new Cache<>();
|
||||||
|
|
||||||
public static Schema getInstance(Schema schema) {
|
public static ObjectSchema getInstance(Schema schema) {
|
||||||
Object key = schema;
|
return cache.get(schema, key -> new ObjectSchema(key));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Schema<T> schema;
|
private final Schema<T> schema;
|
||||||
|
|
|
@ -2,32 +2,20 @@ package io.github.yezhihao.protostar.schema;
|
||||||
|
|
||||||
import io.github.yezhihao.protostar.Schema;
|
import io.github.yezhihao.protostar.Schema;
|
||||||
import io.github.yezhihao.protostar.util.Bcd;
|
import io.github.yezhihao.protostar.util.Bcd;
|
||||||
|
import io.github.yezhihao.protostar.util.Cache;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class StringSchema {
|
public class StringSchema {
|
||||||
|
|
||||||
public static class Chars implements Schema<String> {
|
public static class Chars implements Schema<String> {
|
||||||
private static volatile Map<Object, Chars> cache = new HashMap<>();
|
private static final Cache<String, Chars> cache = new Cache<>();
|
||||||
|
|
||||||
public static Schema<String> getInstance(byte pad, String charset) {
|
public static Chars getInstance(final byte pad, final String charset) {
|
||||||
charset = charset.toLowerCase();
|
String key = new StringBuilder(10).append((char) pad).append('/').append(charset.toLowerCase()).toString();
|
||||||
String key = new StringBuilder(10).append((char) pad).append('/').append(charset).toString();
|
return cache.get(key, k -> new Chars(pad, charset));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final byte pad;
|
private final byte pad;
|
||||||
|
|
|
@ -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<K, V> {
|
||||||
|
|
||||||
|
private volatile HashMap<K, V> 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<K, V> 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<String, Builder[]> 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<Builder> 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<Builder> {
|
||||||
|
private static final BiConsumer<StringBuilder, Object> APPEND_OBJ = (sb, obj) -> sb.append(obj);
|
||||||
|
private static final BiConsumer<StringBuilder, Object> 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<StringBuilder, Object> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue