Skip to content

Instantly share code, notes, and snippets.

@ZenLiuCN
Last active January 11, 2021 02:06
Show Gist options
  • Save ZenLiuCN/2e1000d50a20120c761b27ca2def5157 to your computer and use it in GitHub Desktop.
Save ZenLiuCN/2e1000d50a20120c761b27ca2def5157 to your computer and use it in GitHub Desktop.
package tester;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.DefaultIdStrategy;
import io.protostuff.runtime.IdStrategy;
import io.protostuff.runtime.RuntimeSchema;
import lombok.SneakyThrows;
import lombok.ToString;
import lombok.Value;
import org.jooq.lambda.Seq;
import org.jooq.lambda.Sneaky;
import org.jooq.lambda.tuple.Tuple2;
import org.jooq.lambda.tuple.Tuple3;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.jooq.lambda.tuple.Tuple.tuple;
/**
* @author Zen.Liu
* @apiNote
* @since 2021-01-10
*/
public interface ProtoUtil {
DefaultIdStrategy STRATEGY = new DefaultIdStrategy(
IdStrategy.DEFAULT_FLAGS
| IdStrategy.ALLOW_NULL_ARRAY_ELEMENT
| IdStrategy.MORPH_COLLECTION_INTERFACES
| IdStrategy.MORPH_MAP_INTERFACES
| IdStrategy.MORPH_NON_FINAL_POJOS
);
LinkedBuffer buffer = LinkedBuffer.allocate(512);
Map<String, Schema<Object>> schemaPool = new ConcurrentHashMap<>();
Function<String, Optional<Schema<Object>>> schemaOf = Sneaky.function(util::classFromString).andThen(util::getSchema);
Function<Object, Optional<Schema<Object>>> schemaFrom = Sneaky.function(Object::getClass).andThen(util::getSchema);
static Optional<byte[]> to(Object o) {
Object instance;
try {
Field h = o.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
instance = h.get(o);
} catch (Exception ex) {
instance = o;
}
final Object target = instance;
return schemaFrom.apply(target).map(s -> {
try {
return ProtostuffIOUtil.toByteArray(target, s, buffer);
} finally {
buffer.clear();
}
});
}
static Optional<Object> from(byte[] data, String clz) {
return schemaOf.apply(clz).map(s -> {
Object o = s.newMessage();
ProtostuffIOUtil.mergeFrom(data, o, s);
return o;
});
}
static <T> Optional<T> from(byte[] data, Class<T> clz) {
return util.getSchema(clz).map(s -> {
Object o = s.newMessage();
ProtostuffIOUtil.mergeFrom(data, o, s);
return (T) o;
});
}
final class util {
@SuppressWarnings("unchecked")
static Optional<Schema<Object>> getSchema(Class<?> clz) {
Schema<Object> schema = schemaPool.get(clz.getCanonicalName());
if (schema == null) {
schema = (Schema<Object>) RuntimeSchema.createFrom(clz, STRATEGY);
schemaPool.put(clz.getCanonicalName(), schema);
return Optional.of(schema);
}
return Optional.of(schema);
}
static Class<?> classFromString(String name) throws ClassNotFoundException {
//@formatter:off
if (long.class.getCanonicalName().equals(name)) {return long.class;}
else if (int.class.getCanonicalName().equals(name)) {return int.class;}
else if (byte.class.getCanonicalName().equals(name)) {return byte.class;}
else if (short.class.getCanonicalName().equals(name)) {return short.class;}
else if (boolean.class.getCanonicalName().equals(name)) {return boolean.class;}
else if (double.class.getCanonicalName().equals(name)) {return double.class;}
else if (float.class.getCanonicalName().equals(name)) {return float.class;}
else if (name.endsWith("[]")) {
//array
final String arrayName = "[L" + name.replace(Pattern.quote("[]"), ";");
return Class.forName(arrayName);
}
return name.getClass().getClassLoader().loadClass(name);
//@formatter:on
}
}
@Value(staticConstructor = "of")
class Request {
String domain;
long timestamp = System.currentTimeMillis();
Object[] args;
int[] proxies;
String[] proxyType;
}
@Value(staticConstructor = "of")
class Response {
String domain;
Object result;
int[] proxies;
String[] proxyType;
}
static <T> void registerService(T service, Class<T> serviceKlass) {
}
static <T> T registerClient(Class<T> clientKlass) {
return null;
}
static <T> T delegate(T instance, Class<T> type) {
final Map<String, Object> values = Delegator.copy(instance, type);
return Delegator.proxy(type, values);
}
static <T> T delegate(Class<T> type, Map<String, Object> values) {
return Delegator.proxy(type, values);
}
static Object delegate(Object instance) {
if (instance.getClass().isInterface())
throw new IllegalStateException("no instance will be a interface :" + instance.getClass());
final Class<?>[] interfaces = instance.getClass().getInterfaces();
if (interfaces == null || interfaces.length == 0)
throw new IllegalStateException(" instance implements none interface :" + instance.getClass());
return delegate(instance, (Class<Object>) interfaces[0]);
}
@ToString
final class Delegator implements InvocationHandler {
public final String type;
public final Map<String, Object> values;
Delegator(String type) {
this.type = type;
this.values = new HashMap<>();
}
Delegator(String type, Map<String, Object> values) {
this.type = type;
this.values = values;
}
@SuppressWarnings("unchecked")
public <T> T proxy(Class<T> clz) {
return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[]{clz}, this);
}
@SneakyThrows
public Object delegate() {
final Class<?> aClass = Class.forName(type);
return proxy(aClass);
}
@Override
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
if (m.getName().startsWith("is")) {
return values.get(m.getName().substring(2));
} else if (m.getName().startsWith("get")) {
return values.get(m.getName().substring(3));
} else if (m.getName().startsWith("set")) {
return values.put(m.getName().substring(3), args);
} else if (m.getName().equals("toString")) {
return type + values.toString();
} else {
throw new IllegalStateException("not accepted call:" + m.getName());
// return m.invoke(proxy,args);
}
}
@SuppressWarnings("unchecked")
public static <T> T proxy(Class<T> clz, Map<String, Object> init) {
return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[]{clz}, init != null ? new Delegator(clz.getCanonicalName(), init) : new Delegator(clz.getCanonicalName()));
}
static final Map<String, Function<Object, Map<String, Object>>> copier = new ConcurrentHashMap<>();
public static Map<String, Object> copy(Object instance, Class<?> face) {
if (copier.containsKey(face.getCanonicalName())) {
return copier.get(face.getCanonicalName()).apply(instance);
}
final List<Tuple2<String, Function<Object, Object>>> m = Seq.of(face.getMethods()).map(x ->
x.getName().startsWith("is") ? tuple(x.getName().substring(2), Sneaky.function(x::invoke)) :
x.getName().startsWith("get") ? tuple(x.getName().substring(3), Sneaky.function(x::invoke)) : null
).filter(Objects::nonNull).collect(Collectors.toList());
Function<Object, Map<String, Object>> extractor = o -> {
final Map<String, Object> values = new HashMap<>();
for (Tuple2<String, Function<Object, Object>> func : m) {
values.put(func.v1, func.v2.apply(o));
}
return values;
};
synchronized (copier) {
copier.put(face.getCanonicalName(), extractor);
}
return extractor.apply(instance);
}
}
public interface RsTest {
static void main(String[] args) {
nested();
}
static void nested() {
final SomeOther iface = ProtoUtil.delegate(SomeOther.class, Seq.of(tuple("Id", 1L)).toMap(Tuple2::v1, Tuple2::v2));
final SomeTest someTest = ProtoUtil.delegate(SomeTest.class, Seq.of(
tuple("Id", 1L)
, tuple("Other", Seq.of(tuple("1", iface)).toMap(Tuple2::v1, Tuple2::v2))
, tuple("Others", Arrays.asList(iface, iface))
).toMap(Tuple2::v1, Tuple2::v2));
final Optional<byte[]> data = ProtoUtil.to(someTest);
System.out.println(Arrays.toString(data.get())+":"+data.get().length);
System.out.println(new String(data.get()));
final Optional<Delegator> result = ProtoUtil.from(data.get(), Delegator.class);
final Delegator delegator = result.get();
final SomeTest som = (SomeTest)delegator.delegate();
System.out.println(som);
System.out.println(som.getId());
System.out.println(som.getOther());
System.out.println(som.getOther().get("1"));
System.out.println(som.getOther().get("1") instanceof SomeOther);
System.out.println(som.getOther().get("1").getId());
System.out.println(som.getOthers().size());
System.out.println(som.getOthers().get(0));
}
static void simple() {
final SomeOther iface = ProtoUtil.delegate(SomeOther.class, Seq.of(tuple("Id", 1L)).toMap(Tuple2::v1, Tuple2::v2));
final Optional<byte[]> data = ProtoUtil.to(iface);
System.out.println(Arrays.toString(data.get()));
System.out.println(new String(data.get()));
final Optional<Delegator> result = ProtoUtil.from(data.get(), Delegator.class);
System.out.println(result);
final SomeOther someOther = result.get().proxy(SomeOther.class);
final SomeOther someOther1 = (SomeOther) result.get().delegate();
System.out.println(someOther.getId());
System.out.println(someOther1.getId());
final Map<String, Object> values = Delegator.copy(someOther, SomeOther.class);
System.out.println(values);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment