新增工具类ToStringBuilder,抽象Cache类

master
剑器近 2021-07-01 16:04:44 +08:00
parent c305df04b9
commit 2b6ecfcf1e
6 changed files with 209 additions and 71 deletions

View File

@ -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<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) {
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<T> schema;

View File

@ -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<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) {
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<? extends Converter> 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<T> converter;

View File

@ -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<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) {
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<T> schema;

View File

@ -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<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) {
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;

View File

@ -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();
}
}

View File

@ -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;
}
}
}