sncp
This commit is contained in:
@@ -53,13 +53,13 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
|
|
||||||
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
||||||
|
|
||||||
protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型
|
protected final java.lang.reflect.Type paramHandlerType; // CompletionHandler.completed第一个参数的类型
|
||||||
|
|
||||||
@ClassDepends
|
@ClassDepends
|
||||||
protected final java.lang.reflect.Type returnObjectType; // 返回结果类型 void必须设为null
|
protected final java.lang.reflect.Type returnObjectType; // 返回结果类型 void必须设为null
|
||||||
|
|
||||||
@ClassDepends
|
@ClassDepends
|
||||||
protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型
|
protected final java.lang.reflect.Type returnFutureType; // 返回结果的CompletableFuture的结果泛型类型
|
||||||
|
|
||||||
@ClassDepends
|
@ClassDepends
|
||||||
protected SncpActionServlet(
|
protected SncpActionServlet(
|
||||||
@@ -119,7 +119,7 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
this.paramTypes = types;
|
this.paramTypes = types;
|
||||||
this.paramHandlerIndex = handlerFuncIndex;
|
this.paramHandlerIndex = handlerFuncIndex;
|
||||||
this.paramHandlerClass = handlerFuncClass;
|
this.paramHandlerClass = handlerFuncClass;
|
||||||
this.paramHandlerResultType = handlerResultType;
|
this.paramHandlerType = handlerResultType;
|
||||||
this.returnObjectType =
|
this.returnObjectType =
|
||||||
originalReturnType == void.class || originalReturnType == Void.class ? null : originalReturnType;
|
originalReturnType == void.class || originalReturnType == Void.class ? null : originalReturnType;
|
||||||
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
if (Future.class.isAssignableFrom(method.getReturnType())) {
|
||||||
@@ -134,9 +134,9 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
} else {
|
} else {
|
||||||
throw new SncpException(service.getClass() + " had unknown return genericType in " + method);
|
throw new SncpException(service.getClass() + " had unknown return genericType in " + method);
|
||||||
}
|
}
|
||||||
this.returnFutureResultType = returnType;
|
this.returnFutureType = returnType;
|
||||||
} else {
|
} else {
|
||||||
this.returnFutureResultType = null;
|
this.returnFutureType = null;
|
||||||
}
|
}
|
||||||
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
NonBlocking non = method.getAnnotation(NonBlocking.class);
|
||||||
if (non == null) {
|
if (non == null) {
|
||||||
@@ -150,7 +150,7 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
@Override
|
@Override
|
||||||
public final void execute(SncpRequest request, SncpResponse response) throws IOException {
|
public final void execute(SncpRequest request, SncpResponse response) throws IOException {
|
||||||
if (paramHandlerIndex > 0) {
|
if (paramHandlerIndex > 0) {
|
||||||
response.paramAsyncHandler(paramHandlerClass, paramHandlerResultType);
|
response.paramAsyncHandler(paramHandlerClass, paramHandlerType);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
action(request, response);
|
action(request, response);
|
||||||
@@ -194,7 +194,7 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
*
|
*
|
||||||
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
* public void update(long show, short v2, CompletionHandler<Boolean, TestBean> handler, TestBean bean, String name, int id);
|
||||||
*
|
*
|
||||||
* public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
* public CompletableFuture<String> changeName(TestBean bean, String name, int id);
|
||||||
*
|
*
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
@@ -304,14 +304,14 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
* @Override
|
* @Override
|
||||||
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
* public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||||
* Convert<Reader, Writer> convert = request.getConvert();
|
* Convert<Reader, Writer> convert = request.getConvert();
|
||||||
* Reader in = request.getReader();
|
* Reader in = request.getReader();
|
||||||
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
* TestBean arg1 = convert.convertFrom(paramTypes[1], in);
|
||||||
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
* String arg2 = convert.convertFrom(paramTypes[2], in);
|
||||||
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
* int arg3 = convert.convertFrom(paramTypes[3], in);
|
||||||
* TestService serviceObj = (TestService) service();
|
* TestService serviceObj = (TestService) service();
|
||||||
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
* CompletableFuture future = serviceObj.changeName(arg1, arg2, arg3);
|
||||||
* response.finishFuture(paramHandlerResultType, future);
|
* response.finishFuture(paramHandlerType, future);
|
||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
@@ -349,6 +349,9 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
final String requestDesc = Type.getDescriptor(SncpRequest.class);
|
final String requestDesc = Type.getDescriptor(SncpRequest.class);
|
||||||
final String responseDesc = Type.getDescriptor(SncpResponse.class);
|
final String responseDesc = Type.getDescriptor(SncpResponse.class);
|
||||||
final String serviceDesc = Type.getDescriptor(Service.class);
|
final String serviceDesc = Type.getDescriptor(Service.class);
|
||||||
|
final String handlerDesc = Type.getDescriptor(CompletionHandler.class);
|
||||||
|
final String futureDesc = Type.getDescriptor(Future.class);
|
||||||
|
final String reflectTypeDesc = Type.getDescriptor(java.lang.reflect.Type.class);
|
||||||
final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType());
|
final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType());
|
||||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__"
|
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__"
|
||||||
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
||||||
@@ -368,6 +371,27 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
final java.lang.reflect.Type originalReturnType =
|
final java.lang.reflect.Type originalReturnType =
|
||||||
TypeToken.getGenericType(method.getGenericReturnType(), serviceClass);
|
TypeToken.getGenericType(method.getGenericReturnType(), serviceClass);
|
||||||
|
|
||||||
|
final Class[] paramClasses = method.getParameterTypes();
|
||||||
|
java.lang.reflect.Type paramComposeBeanType0 = SncpRemoteAction.createParamComposeBeanType(
|
||||||
|
serviceImplClass, method, actionid, originalParamTypes, paramClasses);
|
||||||
|
if (paramComposeBeanType0 != null && paramComposeBeanType0 == originalParamTypes[0]) {
|
||||||
|
paramComposeBeanType0 = null;
|
||||||
|
}
|
||||||
|
int handlerFuncIndex = -1;
|
||||||
|
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
||||||
|
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||||
|
if (boolReturnTypeFuture) {
|
||||||
|
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
||||||
|
}
|
||||||
|
if (handlerFuncIndex >= 0) {
|
||||||
|
throw new SncpException(method + " have more than one CompletionHandler type parameter");
|
||||||
|
}
|
||||||
|
Sncp.checkAsyncModifier(paramClasses[i], method);
|
||||||
|
handlerFuncIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final java.lang.reflect.Type paramComposeBeanType = paramComposeBeanType0;
|
||||||
|
|
||||||
if (newClazz == null) {
|
if (newClazz == null) {
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
|
||||||
@@ -434,107 +458,193 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getReader", "()" + readerDesc, false);
|
mv.visitMethodInsn(INVOKEVIRTUAL, requestName, "getReader", "()" + readerDesc, false);
|
||||||
mv.visitVarInsn(ASTORE, 4);
|
mv.visitVarInsn(ASTORE, 4);
|
||||||
}
|
}
|
||||||
int iconst = ICONST_1;
|
if (paramComposeBeanType == null) {
|
||||||
int intconst = 1;
|
int iconst = ICONST_1;
|
||||||
int store = 5; // action的参数个数+2
|
int intconst = 1;
|
||||||
final Class[] paramClasses = method.getParameterTypes();
|
int store = 5; // action的参数个数+2
|
||||||
int[][] codes = new int[paramClasses.length][2];
|
int[][] codes = new int[paramClasses.length][2];
|
||||||
int handlerFuncIndex = -1;
|
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
||||||
for (int i = 0; i < paramClasses.length; i++) { // 反序列化方法的每个参数
|
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
||||||
if (CompletionHandler.class.isAssignableFrom(paramClasses[i])) {
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
if (boolReturnTypeFuture) {
|
mv.visitMethodInsn(
|
||||||
throw new SncpException(method + " have both CompletionHandler and CompletableFuture");
|
INVOKEVIRTUAL,
|
||||||
|
responseName,
|
||||||
|
"getParamAsyncHandler",
|
||||||
|
"()Ljava/nio/channels/CompletionHandler;",
|
||||||
|
false);
|
||||||
|
mv.visitTypeInsn(
|
||||||
|
CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||||
|
mv.visitVarInsn(ASTORE, store);
|
||||||
|
codes[i] = new int[] {ALOAD, store};
|
||||||
|
store++;
|
||||||
|
iconst++;
|
||||||
|
intconst++;
|
||||||
|
mv.visitVarInsn(ALOAD, 3);
|
||||||
|
mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class)));
|
||||||
|
mv.visitVarInsn(ALOAD, 4);
|
||||||
|
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||||
|
mv.visitInsn(POP);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (handlerFuncIndex >= 0) {
|
mv.visitVarInsn(ALOAD, 3);
|
||||||
throw new SncpException(method + " have more than one CompletionHandler type parameter");
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
||||||
|
|
||||||
|
if (intconst < 6) {
|
||||||
|
mv.visitInsn(ICONST_0 + intconst);
|
||||||
|
} else if (iconst <= Byte.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(BIPUSH, intconst);
|
||||||
|
} else if (iconst <= Short.MAX_VALUE) {
|
||||||
|
mv.visitIntInsn(SIPUSH, intconst);
|
||||||
|
} else {
|
||||||
|
mv.visitLdcInsn(intconst);
|
||||||
}
|
}
|
||||||
Sncp.checkAsyncModifier(paramClasses[i], method);
|
mv.visitInsn(AALOAD);
|
||||||
handlerFuncIndex = i;
|
mv.visitVarInsn(ALOAD, 4);
|
||||||
mv.visitVarInsn(ALOAD, 2);
|
|
||||||
mv.visitMethodInsn(
|
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||||
INVOKEVIRTUAL,
|
int load = ALOAD;
|
||||||
responseName,
|
int v = 0;
|
||||||
"getParamAsyncHandler",
|
if (paramClasses[i].isPrimitive()) {
|
||||||
"()Ljava/nio/channels/CompletionHandler;",
|
int storecode = ISTORE;
|
||||||
false);
|
load = ILOAD;
|
||||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
if (paramClasses[i] == long.class) {
|
||||||
mv.visitVarInsn(ASTORE, store);
|
storecode = LSTORE;
|
||||||
codes[i] = new int[] {ALOAD, store};
|
load = LLOAD;
|
||||||
store++;
|
v = 1;
|
||||||
|
} else if (paramClasses[i] == float.class) {
|
||||||
|
storecode = FSTORE;
|
||||||
|
load = FLOAD;
|
||||||
|
v = 1;
|
||||||
|
} else if (paramClasses[i] == double.class) {
|
||||||
|
storecode = DSTORE;
|
||||||
|
load = DLOAD;
|
||||||
|
v = 1;
|
||||||
|
}
|
||||||
|
Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]);
|
||||||
|
String bigPrimitiveName =
|
||||||
|
bigPrimitiveClass.getName().replace('.', '/');
|
||||||
|
try {
|
||||||
|
Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value");
|
||||||
|
mv.visitTypeInsn(CHECKCAST, bigPrimitiveName);
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
INVOKEVIRTUAL,
|
||||||
|
bigPrimitiveName,
|
||||||
|
pm.getName(),
|
||||||
|
Type.getMethodDescriptor(pm),
|
||||||
|
false);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new SncpException(ex); // 不可能会发生
|
||||||
|
}
|
||||||
|
mv.visitVarInsn(storecode, store);
|
||||||
|
} else {
|
||||||
|
mv.visitTypeInsn(
|
||||||
|
CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
||||||
|
mv.visitVarInsn(ASTORE, store); //
|
||||||
|
}
|
||||||
|
codes[i] = new int[] {load, store};
|
||||||
|
store += v;
|
||||||
iconst++;
|
iconst++;
|
||||||
intconst++;
|
intconst++;
|
||||||
mv.visitVarInsn(ALOAD, 3);
|
store++;
|
||||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(CompletionHandler.class)));
|
|
||||||
mv.visitVarInsn(ALOAD, 4);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
|
||||||
mv.visitInsn(POP);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
mv.visitVarInsn(ALOAD, 3);
|
{ // 调用service
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitFieldInsn(GETFIELD, newDynName, "paramTypes", "[Ljava/lang/reflect/Type;");
|
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()" + serviceDesc, false);
|
||||||
|
mv.visitTypeInsn(CHECKCAST, serviceImpTypeName);
|
||||||
|
mv.visitVarInsn(ASTORE, store);
|
||||||
|
|
||||||
if (intconst < 6) {
|
mv.visitVarInsn(ALOAD, store);
|
||||||
mv.visitInsn(ICONST_0 + intconst);
|
for (int[] j : codes) {
|
||||||
} else if (iconst <= Byte.MAX_VALUE) {
|
mv.visitVarInsn(j[0], j[1]);
|
||||||
mv.visitIntInsn(BIPUSH, intconst);
|
|
||||||
} else if (iconst <= Short.MAX_VALUE) {
|
|
||||||
mv.visitIntInsn(SIPUSH, intconst);
|
|
||||||
} else {
|
|
||||||
mv.visitLdcInsn(intconst);
|
|
||||||
}
|
|
||||||
mv.visitInsn(AALOAD);
|
|
||||||
mv.visitVarInsn(ALOAD, 4);
|
|
||||||
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
|
||||||
int load = ALOAD;
|
|
||||||
int v = 0;
|
|
||||||
if (paramClasses[i].isPrimitive()) {
|
|
||||||
int storecode = ISTORE;
|
|
||||||
load = ILOAD;
|
|
||||||
if (paramClasses[i] == long.class) {
|
|
||||||
storecode = LSTORE;
|
|
||||||
load = LLOAD;
|
|
||||||
v = 1;
|
|
||||||
} else if (paramClasses[i] == float.class) {
|
|
||||||
storecode = FSTORE;
|
|
||||||
load = FLOAD;
|
|
||||||
v = 1;
|
|
||||||
} else if (paramClasses[i] == double.class) {
|
|
||||||
storecode = DSTORE;
|
|
||||||
load = DLOAD;
|
|
||||||
v = 1;
|
|
||||||
}
|
}
|
||||||
Class bigPrimitiveClass = TypeToken.primitiveToWrapper(paramClasses[i]);
|
mv.visitMethodInsn(
|
||||||
String bigPrimitiveName = bigPrimitiveClass.getName().replace('.', '/');
|
serviceImplClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL,
|
||||||
try {
|
serviceImpTypeName,
|
||||||
Method pm = bigPrimitiveClass.getMethod(paramClasses[i].getSimpleName() + "Value");
|
method.getName(),
|
||||||
mv.visitTypeInsn(CHECKCAST, bigPrimitiveName);
|
Type.getMethodDescriptor(method),
|
||||||
|
serviceImplClass.isInterface());
|
||||||
|
store++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getReturnType() != void.class) {
|
||||||
|
final Class returnClass = method.getReturnType();
|
||||||
|
if (returnClass.isPrimitive()) {
|
||||||
|
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
||||||
|
try {
|
||||||
|
Method vo = bigClass.getMethod("valueOf", returnClass);
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
INVOKESTATIC,
|
||||||
|
bigClass.getName().replace('.', '/'),
|
||||||
|
vo.getName(),
|
||||||
|
Type.getMethodDescriptor(vo),
|
||||||
|
false);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new SncpException(ex); // 不可能会发生
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitVarInsn(ASTORE, store); // 11
|
||||||
|
|
||||||
|
if (boolReturnTypeFuture) { // 返回类型为Future
|
||||||
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureType", reflectTypeDesc);
|
||||||
|
mv.visitVarInsn(ALOAD, store);
|
||||||
mv.visitMethodInsn(
|
mv.visitMethodInsn(
|
||||||
INVOKEVIRTUAL, bigPrimitiveName, pm.getName(), Type.getMethodDescriptor(pm), false);
|
INVOKEVIRTUAL,
|
||||||
} catch (Exception ex) {
|
responseName,
|
||||||
throw new SncpException(ex); // 不可能会发生
|
"finishFuture",
|
||||||
|
"(" + reflectTypeDesc + futureDesc + ")V",
|
||||||
|
false);
|
||||||
|
} else if (handlerFuncIndex >= 0) { // 参数有CompletionHandler
|
||||||
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
|
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||||
|
} else { // 普通对象
|
||||||
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", reflectTypeDesc);
|
||||||
|
mv.visitVarInsn(ALOAD, store);
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
INVOKEVIRTUAL,
|
||||||
|
responseName,
|
||||||
|
"finish",
|
||||||
|
"(" + reflectTypeDesc + "Ljava/lang/Object;)V",
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
mv.visitVarInsn(storecode, store);
|
} else { // void返回类型
|
||||||
} else {
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
mv.visitTypeInsn(CHECKCAST, paramClasses[i].getName().replace('.', '/'));
|
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||||
mv.visitVarInsn(ASTORE, store); //
|
|
||||||
}
|
}
|
||||||
codes[i] = new int[] {load, store};
|
} else { // 动态生成的参数组合类
|
||||||
store += v;
|
Class paramComposeBeanClass = TypeToken.typeToClass(paramComposeBeanType);
|
||||||
iconst++;
|
String paramComposeBeanName =
|
||||||
intconst++;
|
paramComposeBeanClass.getName().replace('.', '/');
|
||||||
store++;
|
mv.visitVarInsn(ALOAD, 3); // convert
|
||||||
}
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
{ // 调用service
|
mv.visitFieldInsn(GETFIELD, newDynName, "paramComposeType", reflectTypeDesc);
|
||||||
|
mv.visitVarInsn(ALOAD, 4); // reader
|
||||||
|
mv.visitMethodInsn(INVOKEVIRTUAL, convertName, "convertFrom", convertFromDesc, false);
|
||||||
|
mv.visitTypeInsn(CHECKCAST, paramComposeBeanName);
|
||||||
|
mv.visitVarInsn(ASTORE, 5); // paramBean
|
||||||
|
|
||||||
|
// 给CompletionHandler参数赋值
|
||||||
|
mv.visitVarInsn(ALOAD, 5);
|
||||||
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
|
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "getParamAsyncHandler", "()" + handlerDesc, false);
|
||||||
|
mv.visitFieldInsn(PUTFIELD, paramComposeBeanName, "arg3", handlerDesc);
|
||||||
|
|
||||||
|
// 调用service()
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()" + serviceDesc, false);
|
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()" + serviceDesc, false);
|
||||||
mv.visitTypeInsn(CHECKCAST, serviceImpTypeName);
|
mv.visitTypeInsn(CHECKCAST, serviceImpTypeName);
|
||||||
mv.visitVarInsn(ASTORE, store);
|
mv.visitVarInsn(ASTORE, 6); // service
|
||||||
|
|
||||||
mv.visitVarInsn(ALOAD, store);
|
// 执行service方法
|
||||||
for (int[] j : codes) {
|
mv.visitVarInsn(ALOAD, 6); // service
|
||||||
mv.visitVarInsn(j[0], j[1]);
|
for (int i = 1; i <= paramClasses.length; i++) {
|
||||||
|
mv.visitVarInsn(ALOAD, 5); // paramBean
|
||||||
|
mv.visitFieldInsn(
|
||||||
|
GETFIELD, paramComposeBeanName, "arg" + i, Type.getDescriptor(paramClasses[i - 1]));
|
||||||
}
|
}
|
||||||
mv.visitMethodInsn(
|
mv.visitMethodInsn(
|
||||||
serviceImplClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL,
|
serviceImplClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL,
|
||||||
@@ -542,58 +652,60 @@ public abstract class SncpActionServlet extends SncpServlet {
|
|||||||
method.getName(),
|
method.getName(),
|
||||||
Type.getMethodDescriptor(method),
|
Type.getMethodDescriptor(method),
|
||||||
serviceImplClass.isInterface());
|
serviceImplClass.isInterface());
|
||||||
store++;
|
|
||||||
}
|
|
||||||
if (method.getReturnType() != void.class) {
|
|
||||||
final Class returnClass = method.getReturnType();
|
|
||||||
if (returnClass.isPrimitive()) {
|
|
||||||
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
|
||||||
try {
|
|
||||||
Method vo = bigClass.getMethod("valueOf", returnClass);
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
INVOKESTATIC,
|
|
||||||
bigClass.getName().replace('.', '/'),
|
|
||||||
vo.getName(),
|
|
||||||
Type.getMethodDescriptor(vo),
|
|
||||||
false);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new SncpException(ex); // 不可能会发生
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mv.visitVarInsn(ASTORE, store); // 11
|
|
||||||
|
|
||||||
if (boolReturnTypeFuture) { // 返回类型为Future
|
// 返回
|
||||||
mv.visitVarInsn(ALOAD, 2);
|
if (method.getReturnType() != void.class) {
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
final Class returnClass = method.getReturnType();
|
||||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureResultType", "Ljava/lang/reflect/Type;");
|
if (returnClass.isPrimitive()) {
|
||||||
mv.visitVarInsn(ALOAD, store);
|
Class bigClass = TypeToken.primitiveToWrapper(returnClass);
|
||||||
mv.visitMethodInsn(
|
try {
|
||||||
INVOKEVIRTUAL,
|
Method vo = bigClass.getMethod("valueOf", returnClass);
|
||||||
responseName,
|
mv.visitMethodInsn(
|
||||||
"finishFuture",
|
INVOKESTATIC,
|
||||||
"(Ljava/lang/reflect/Type;Ljava/util/concurrent/Future;)V",
|
bigClass.getName().replace('.', '/'),
|
||||||
false);
|
vo.getName(),
|
||||||
} else if (handlerFuncIndex >= 0) { // 参数有CompletionHandler
|
Type.getMethodDescriptor(vo),
|
||||||
mv.visitVarInsn(ALOAD, 2);
|
false);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new SncpException(ex); // 不可能会发生
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitVarInsn(ASTORE, 7); // returnObject
|
||||||
|
|
||||||
|
if (boolReturnTypeFuture) { // 返回类型为Future
|
||||||
|
mv.visitVarInsn(ALOAD, 2); // response
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitFieldInsn(GETFIELD, newDynName, "returnFutureType", reflectTypeDesc);
|
||||||
|
mv.visitVarInsn(ALOAD, 7); // returnObject
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
INVOKEVIRTUAL,
|
||||||
|
responseName,
|
||||||
|
"finishFuture",
|
||||||
|
"(" + reflectTypeDesc + futureDesc + ")V",
|
||||||
|
false);
|
||||||
|
} else if (handlerFuncIndex >= 0) { // 参数有CompletionHandler
|
||||||
|
mv.visitVarInsn(ALOAD, 2); // response
|
||||||
|
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||||
|
} else { // 普通对象
|
||||||
|
mv.visitVarInsn(ALOAD, 2);
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", reflectTypeDesc);
|
||||||
|
mv.visitVarInsn(ALOAD, 7); // returnObject
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
INVOKEVIRTUAL,
|
||||||
|
responseName,
|
||||||
|
"finish",
|
||||||
|
"(" + reflectTypeDesc + "Ljava/lang/Object;)V",
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
} else { // void返回类型
|
||||||
|
mv.visitVarInsn(ALOAD, 2); // response
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
||||||
} else { // 普通对象
|
|
||||||
mv.visitVarInsn(ALOAD, 2);
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
|
||||||
mv.visitFieldInsn(GETFIELD, newDynName, "returnObjectType", "Ljava/lang/reflect/Type;");
|
|
||||||
mv.visitVarInsn(ALOAD, store);
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
INVOKEVIRTUAL,
|
|
||||||
responseName,
|
|
||||||
"finish",
|
|
||||||
"(Ljava/lang/reflect/Type;Ljava/lang/Object;)V",
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
} else { // void返回类型
|
|
||||||
mv.visitVarInsn(ALOAD, 2);
|
|
||||||
mv.visitMethodInsn(INVOKEVIRTUAL, responseName, "finishVoid", "()V", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mv.visitInsn(RETURN);
|
mv.visitInsn(RETURN);
|
||||||
mv.visitMaxs(8, store);
|
mv.visitMaxs(8, 8);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
|
|||||||
@@ -60,6 +60,9 @@ public final class SncpRemoteAction {
|
|||||||
// 参数数量为0: 值为null; 参数数量为1且参数类型为JavaBean: 值为第一个参数的类型; 其他情况: 动态生成的Object类
|
// 参数数量为0: 值为null; 参数数量为1且参数类型为JavaBean: 值为第一个参数的类型; 其他情况: 动态生成的Object类
|
||||||
protected final Type paramComposeBeanType;
|
protected final Type paramComposeBeanType;
|
||||||
|
|
||||||
|
// 只有paramComposeBeanType为动态生成的组合类时才有值;
|
||||||
|
protected final Creator paramComposeBeanCreator;
|
||||||
|
|
||||||
protected final int paramHandlerIndex;
|
protected final int paramHandlerIndex;
|
||||||
|
|
||||||
protected final int paramHandlerAttachIndex;
|
protected final int paramHandlerAttachIndex;
|
||||||
@@ -72,9 +75,9 @@ public final class SncpRemoteAction {
|
|||||||
|
|
||||||
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
protected final Class<? extends CompletionHandler> paramHandlerClass; // CompletionHandler参数的类型
|
||||||
|
|
||||||
protected final java.lang.reflect.Type paramHandlerResultType; // CompletionHandler.completed第一个参数的类型
|
protected final java.lang.reflect.Type paramHandlerType; // CompletionHandler.completed第一个参数的类型
|
||||||
|
|
||||||
protected final java.lang.reflect.Type returnFutureResultType; // 返回结果的CompletableFuture的结果泛型类型
|
protected final java.lang.reflect.Type returnFutureType; // 返回结果的CompletableFuture的结果泛型类型
|
||||||
|
|
||||||
protected final Class<? extends Future> returnFutureClass; // 返回结果的CompletableFuture类型
|
protected final Class<? extends Future> returnFutureClass; // 返回结果的CompletableFuture类型
|
||||||
|
|
||||||
@@ -95,8 +98,10 @@ public final class SncpRemoteAction {
|
|||||||
this.returnObjectType = rt == void.class || rt == Void.class ? null : rt;
|
this.returnObjectType = rt == void.class || rt == Void.class ? null : rt;
|
||||||
this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass);
|
this.paramTypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceImplClass);
|
||||||
this.paramClasses = method.getParameterTypes();
|
this.paramClasses = method.getParameterTypes();
|
||||||
this.paramComposeBeanType =
|
Type pt = createParamComposeBeanType(serviceImplClass, method, actionid, paramTypes, paramClasses);
|
||||||
createParamComposeBeanType(serviceImplClass, method, actionid, paramTypes, paramClasses);
|
this.paramComposeBeanType = pt;
|
||||||
|
this.paramComposeBeanCreator =
|
||||||
|
(pt == null || pt == paramTypes[0]) ? null : Creator.create(TypeToken.typeToClass(pt), 1);
|
||||||
this.method = method;
|
this.method = method;
|
||||||
Annotation[][] anns = method.getParameterAnnotations();
|
Annotation[][] anns = method.getParameterAnnotations();
|
||||||
int topicAddrIndex = -1;
|
int topicAddrIndex = -1;
|
||||||
@@ -186,7 +191,7 @@ public final class SncpRemoteAction {
|
|||||||
this.paramAddressSourceIndex = sourceAddrIndex;
|
this.paramAddressSourceIndex = sourceAddrIndex;
|
||||||
this.paramHandlerIndex = handlerFuncIndex;
|
this.paramHandlerIndex = handlerFuncIndex;
|
||||||
this.paramHandlerClass = handlerFuncClass;
|
this.paramHandlerClass = handlerFuncClass;
|
||||||
this.paramHandlerResultType = handlerResultType;
|
this.paramHandlerType = handlerResultType;
|
||||||
this.paramHandlerAttachIndex = handlerAttachIndex;
|
this.paramHandlerAttachIndex = handlerAttachIndex;
|
||||||
this.header = SncpHeader.create(
|
this.header = SncpHeader.create(
|
||||||
sncpClient == null ? null : sncpClient.getClientSncpAddress(),
|
sncpClient == null ? null : sncpClient.getClientSncpAddress(),
|
||||||
@@ -209,7 +214,7 @@ public final class SncpRemoteAction {
|
|||||||
} else {
|
} else {
|
||||||
throw new SncpException(serviceImplClass + " had unknown return genericType in " + method);
|
throw new SncpException(serviceImplClass + " had unknown return genericType in " + method);
|
||||||
}
|
}
|
||||||
this.returnFutureResultType = returnType;
|
this.returnFutureType = returnType;
|
||||||
this.returnFutureClass = method.getReturnType().isAssignableFrom(CompletableFuture.class)
|
this.returnFutureClass = method.getReturnType().isAssignableFrom(CompletableFuture.class)
|
||||||
? CompletableFuture.class
|
? CompletableFuture.class
|
||||||
: (Class) method.getReturnType();
|
: (Class) method.getReturnType();
|
||||||
@@ -220,7 +225,7 @@ public final class SncpRemoteAction {
|
|||||||
throw new SncpException(serviceImplClass + " return must be CompletableFuture or subclass");
|
throw new SncpException(serviceImplClass + " return must be CompletableFuture or subclass");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.returnFutureResultType = null;
|
this.returnFutureType = null;
|
||||||
this.returnFutureClass = null;
|
this.returnFutureClass = null;
|
||||||
this.returnFutureCreator = null;
|
this.returnFutureCreator = null;
|
||||||
}
|
}
|
||||||
@@ -247,7 +252,7 @@ public final class SncpRemoteAction {
|
|||||||
// 动态生成组合JavaBean类
|
// 动态生成组合JavaBean类
|
||||||
final Class serviceClass = resourceType.getClass();
|
final Class serviceClass = resourceType.getClass();
|
||||||
final String columnDesc = org.redkale.asm.Type.getDescriptor(ConvertColumn.class);
|
final String columnDesc = org.redkale.asm.Type.getDescriptor(ConvertColumn.class);
|
||||||
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionParamBean__"
|
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionParamBean_"
|
||||||
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
+ resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
|
||||||
try {
|
try {
|
||||||
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
Class clz = RedkaleClassLoader.findDynClass(newDynName.replace('/', '.'));
|
||||||
@@ -278,7 +283,7 @@ public final class SncpRemoteAction {
|
|||||||
av.visitEnd();
|
av.visitEnd();
|
||||||
fv.visitEnd();
|
fv.visitEnd();
|
||||||
}
|
}
|
||||||
{ // 空参数构造函数
|
{ // 空参数的构造函数
|
||||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null));
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||||
@@ -286,7 +291,7 @@ public final class SncpRemoteAction {
|
|||||||
mv.visitMaxs(1, 1);
|
mv.visitMaxs(1, 1);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
{ // 带参数构造函数
|
{ // 一个参数的构造函数
|
||||||
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "([Ljava/lang/Object;)V", null, null));
|
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "([Ljava/lang/Object;)V", null, null));
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||||
@@ -306,13 +311,16 @@ public final class SncpRemoteAction {
|
|||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
|
|
||||||
byte[] bytes = cw.toByteArray();
|
byte[] bytes = cw.toByteArray();
|
||||||
Class newClazz = new ClassLoader(serviceClass.getClassLoader()) {
|
Class newClazz = new ClassLoader(Thread.currentThread().getContextClassLoader()) {
|
||||||
public final Class<?> loadClass(String name, byte[] b) {
|
public final Class<?> loadClass(String name, byte[] b) {
|
||||||
return defineClass(name, b, 0, b.length);
|
return defineClass(name, b, 0, b.length);
|
||||||
}
|
}
|
||||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||||
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||||
|
Creator.load(newClazz);
|
||||||
|
ProtobufFactory.root().loadDecoder(newClazz);
|
||||||
|
ProtobufFactory.root().loadEncoder(newClazz);
|
||||||
return newClazz;
|
return newClazz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public class SncpRemoteInfo<S extends Service> {
|
|||||||
handler.completed(
|
handler.completed(
|
||||||
v == null
|
v == null
|
||||||
? null
|
? null
|
||||||
: convert.convertFrom(action.paramHandlerResultType, v, 1, v.length - 1),
|
: convert.convertFrom(action.paramHandlerType, v, 1, v.length - 1),
|
||||||
attach);
|
attach);
|
||||||
} else {
|
} else {
|
||||||
handler.failed(t, attach);
|
handler.failed(t, attach);
|
||||||
@@ -144,7 +144,7 @@ public class SncpRemoteInfo<S extends Service> {
|
|||||||
if (action.returnFutureClass == CompletableFuture.class) {
|
if (action.returnFutureClass == CompletableFuture.class) {
|
||||||
// v,length-1为了读掉(byte)0
|
// v,length-1为了读掉(byte)0
|
||||||
return (T) future.thenApply(
|
return (T) future.thenApply(
|
||||||
v -> v == null ? null : convert.convertFrom(action.returnFutureResultType, v, 1, v.length - 1));
|
v -> v == null ? null : convert.convertFrom(action.returnFutureType, v, 1, v.length - 1));
|
||||||
} else {
|
} else {
|
||||||
final CompletableFuture returnFuture = action.returnFutureCreator.create();
|
final CompletableFuture returnFuture = action.returnFutureCreator.create();
|
||||||
future.whenComplete((v, t) -> {
|
future.whenComplete((v, t) -> {
|
||||||
@@ -153,7 +153,7 @@ public class SncpRemoteInfo<S extends Service> {
|
|||||||
returnFuture.complete(
|
returnFuture.complete(
|
||||||
v == null
|
v == null
|
||||||
? null
|
? null
|
||||||
: convert.convertFrom(action.returnFutureResultType, v, 1, v.length - 1));
|
: convert.convertFrom(action.returnFutureType, v, 1, v.length - 1));
|
||||||
} else {
|
} else {
|
||||||
returnFuture.completeExceptionally(t);
|
returnFuture.completeExceptionally(t);
|
||||||
}
|
}
|
||||||
@@ -256,8 +256,13 @@ public class SncpRemoteInfo<S extends Service> {
|
|||||||
byte[] body = null;
|
byte[] body = null;
|
||||||
if (myParamTypes.length > 0) { // 存在参数
|
if (myParamTypes.length > 0) { // 存在参数
|
||||||
ProtobufWriter writer = convert.pollWriter();
|
ProtobufWriter writer = convert.pollWriter();
|
||||||
for (int i = 0; i < params.length; i++) { // service方法的参数
|
if (action.paramComposeBeanCreator != null) {
|
||||||
convert.convertTo(writer, myParamTypes[i], params[i]);
|
Object paramBean = action.paramComposeBeanCreator.create(params);
|
||||||
|
convert.convertTo(writer, action.paramComposeBeanType, paramBean);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < params.length; i++) { // service方法的参数
|
||||||
|
convert.convertTo(writer, myParamTypes[i], params[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
body = writer.toByteArray().content();
|
body = writer.toByteArray().content();
|
||||||
convert.offerWriter(writer);
|
convert.offerWriter(writer);
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.redkale.util;
|
package org.redkale.util;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.AbstractMap.SimpleEntry;
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
@@ -360,6 +358,16 @@ public interface Creator<T> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (constructor0 == null && paramCount == 1) {
|
||||||
|
for (Constructor c : cs) {
|
||||||
|
int cc = c.getParameterCount();
|
||||||
|
if (cc == 1 && c.getParameterTypes()[0] == Object[].class) {
|
||||||
|
constructor0 = c;
|
||||||
|
constructorParameters0 = new SimpleEntry[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (constructor0 == null) { // 4、查找非private带ConstructorParameters的构造函数
|
if (constructor0 == null) { // 4、查找非private带ConstructorParameters的构造函数
|
||||||
for (Constructor c : clazz.getDeclaredConstructors()) {
|
for (Constructor c : clazz.getDeclaredConstructors()) {
|
||||||
@@ -439,12 +447,14 @@ public interface Creator<T> {
|
|||||||
int paramLen = constructorParameters.length;
|
int paramLen = constructorParameters.length;
|
||||||
Asms.visitInsn(mv, paramLen);
|
Asms.visitInsn(mv, paramLen);
|
||||||
mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
|
mv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
|
||||||
|
|
||||||
for (int i = 0; i < constructorParameters.length; i++) {
|
for (int i = 0; i < constructorParameters.length; i++) {
|
||||||
final Class pt = constructorParameters[i].getValue();
|
|
||||||
mv.visitInsn(DUP);
|
mv.visitInsn(DUP);
|
||||||
Asms.visitInsn(mv, i);
|
Asms.visitInsn(mv, i);
|
||||||
Asms.visitFieldInsn(mv, pt);
|
if (constructorParameters[i] == null) {
|
||||||
|
mv.visitLdcInsn(Type.getType("[Ljava/lang/Object;"));
|
||||||
|
} else {
|
||||||
|
Asms.visitFieldInsn(mv, constructorParameters[i].getValue());
|
||||||
|
}
|
||||||
mv.visitInsn(AASTORE);
|
mv.visitInsn(AASTORE);
|
||||||
}
|
}
|
||||||
mv.visitInsn(ARETURN);
|
mv.visitInsn(ARETURN);
|
||||||
@@ -454,7 +464,7 @@ public interface Creator<T> {
|
|||||||
{ // create 方法
|
{ // create 方法
|
||||||
mv = cw.visitMethod(
|
mv = cw.visitMethod(
|
||||||
ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null);
|
ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)L" + interName + ";", null, null);
|
||||||
if (constructorParameters.length > 0) {
|
if (constructorParameters.length > 0 && constructorParameters[0] != null) {
|
||||||
av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true);
|
av0 = mv.visitAnnotation(Type.getDescriptor(ConstructorParameters.class), true);
|
||||||
AnnotationVisitor av1 = av0.visitArray("value");
|
AnnotationVisitor av1 = av0.visitArray("value");
|
||||||
for (SimpleEntry<String, Class> n : constructorParameters) {
|
for (SimpleEntry<String, Class> n : constructorParameters) {
|
||||||
@@ -463,81 +473,84 @@ public interface Creator<T> {
|
|||||||
av1.visitEnd();
|
av1.visitEnd();
|
||||||
av0.visitEnd();
|
av0.visitEnd();
|
||||||
}
|
}
|
||||||
{ // 有Primitive数据类型且值为null的参数需要赋默认值
|
// 有Primitive数据类型且值为null的参数需要赋默认值
|
||||||
for (int i = 0; i < constructorParameters.length; i++) {
|
for (int i = 0; i < constructorParameters.length; i++) {
|
||||||
final Class pt = constructorParameters[i].getValue();
|
if (constructorParameters[i] == null) {
|
||||||
if (!pt.isPrimitive()) {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mv.visitVarInsn(ALOAD, 1);
|
|
||||||
Asms.visitInsn(mv, i);
|
|
||||||
mv.visitInsn(AALOAD);
|
|
||||||
Label lab = new Label();
|
|
||||||
mv.visitJumpInsn(IFNONNULL, lab);
|
|
||||||
mv.visitVarInsn(ALOAD, 1);
|
|
||||||
Asms.visitInsn(mv, i);
|
|
||||||
if (pt == int.class) {
|
|
||||||
mv.visitInsn(ICONST_0);
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
|
||||||
} else if (pt == long.class) {
|
|
||||||
mv.visitInsn(LCONST_0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
|
|
||||||
} else if (pt == boolean.class) {
|
|
||||||
mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
|
|
||||||
} else if (pt == short.class) {
|
|
||||||
mv.visitInsn(ICONST_0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
|
|
||||||
} else if (pt == float.class) {
|
|
||||||
mv.visitInsn(FCONST_0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
|
||||||
} else if (pt == byte.class) {
|
|
||||||
mv.visitInsn(ICONST_0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
|
|
||||||
} else if (pt == double.class) {
|
|
||||||
mv.visitInsn(DCONST_0);
|
|
||||||
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
|
||||||
} else if (pt == char.class) {
|
|
||||||
mv.visitInsn(ICONST_0);
|
|
||||||
mv.visitMethodInsn(
|
|
||||||
INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
|
||||||
}
|
|
||||||
mv.visitInsn(AASTORE);
|
|
||||||
mv.visitLabel(lab);
|
|
||||||
}
|
}
|
||||||
|
final Class pt = constructorParameters[i].getValue();
|
||||||
|
if (!pt.isPrimitive()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mv.visitVarInsn(ALOAD, 1);
|
||||||
|
Asms.visitInsn(mv, i);
|
||||||
|
mv.visitInsn(AALOAD);
|
||||||
|
Label lab = new Label();
|
||||||
|
mv.visitJumpInsn(IFNONNULL, lab);
|
||||||
|
mv.visitVarInsn(ALOAD, 1);
|
||||||
|
Asms.visitInsn(mv, i);
|
||||||
|
if (pt == int.class) {
|
||||||
|
mv.visitInsn(ICONST_0);
|
||||||
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
|
||||||
|
} else if (pt == long.class) {
|
||||||
|
mv.visitInsn(LCONST_0);
|
||||||
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false);
|
||||||
|
} else if (pt == boolean.class) {
|
||||||
|
mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
|
||||||
|
} else if (pt == short.class) {
|
||||||
|
mv.visitInsn(ICONST_0);
|
||||||
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false);
|
||||||
|
} else if (pt == float.class) {
|
||||||
|
mv.visitInsn(FCONST_0);
|
||||||
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
|
||||||
|
} else if (pt == byte.class) {
|
||||||
|
mv.visitInsn(ICONST_0);
|
||||||
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false);
|
||||||
|
} else if (pt == double.class) {
|
||||||
|
mv.visitInsn(DCONST_0);
|
||||||
|
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
|
||||||
|
} else if (pt == char.class) {
|
||||||
|
mv.visitInsn(ICONST_0);
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
|
||||||
|
}
|
||||||
|
mv.visitInsn(AASTORE);
|
||||||
|
mv.visitLabel(lab);
|
||||||
}
|
}
|
||||||
mv.visitTypeInsn(NEW, interName);
|
mv.visitTypeInsn(NEW, interName);
|
||||||
mv.visitInsn(DUP);
|
mv.visitInsn(DUP);
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
{
|
for (int i = 0; i < constructorParameters.length; i++) {
|
||||||
for (int i = 0; i < constructorParameters.length; i++) {
|
if (constructorParameters[i] == null) {
|
||||||
mv.visitVarInsn(ALOAD, 1);
|
mv.visitVarInsn(ALOAD, 1);
|
||||||
Asms.visitInsn(mv, i);
|
break;
|
||||||
mv.visitInsn(AALOAD);
|
}
|
||||||
final Class ct = constructorParameters[i].getValue();
|
mv.visitVarInsn(ALOAD, 1);
|
||||||
if (ct.isPrimitive()) {
|
Asms.visitInsn(mv, i);
|
||||||
final Class bigct = TypeToken.primitiveToWrapper(ct);
|
mv.visitInsn(AALOAD);
|
||||||
mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/'));
|
final Class ct = constructorParameters[i].getValue();
|
||||||
try {
|
if (ct.isPrimitive()) {
|
||||||
Method pm = bigct.getMethod(ct.getSimpleName() + "Value");
|
final Class bigct = TypeToken.primitiveToWrapper(ct);
|
||||||
mv.visitMethodInsn(
|
mv.visitTypeInsn(CHECKCAST, bigct.getName().replace('.', '/'));
|
||||||
INVOKEVIRTUAL,
|
try {
|
||||||
bigct.getName().replace('.', '/'),
|
Method pm = bigct.getMethod(ct.getSimpleName() + "Value");
|
||||||
pm.getName(),
|
mv.visitMethodInsn(
|
||||||
Type.getMethodDescriptor(pm),
|
INVOKEVIRTUAL,
|
||||||
false);
|
bigct.getName().replace('.', '/'),
|
||||||
} catch (Exception ex) {
|
pm.getName(),
|
||||||
throw new RedkaleException(ex); // 不可能会发生
|
Type.getMethodDescriptor(pm),
|
||||||
}
|
false);
|
||||||
} else {
|
} catch (Exception ex) {
|
||||||
mv.visitTypeInsn(CHECKCAST, ct.getName().replace('.', '/'));
|
throw new RedkaleException(ex); // 不可能会发生
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mv.visitTypeInsn(CHECKCAST, ct.getName().replace('.', '/'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, interName, "<init>", Type.getConstructorDescriptor(constructor), false);
|
mv.visitMethodInsn(INVOKESPECIAL, interName, "<init>", Type.getConstructorDescriptor(constructor), false);
|
||||||
mv.visitInsn(ARETURN);
|
mv.visitInsn(ARETURN);
|
||||||
mv.visitMaxs((constructorParameters.length > 0 ? (constructorParameters.length + 3) : 2), 2);
|
mv.visitMaxs(3, 2);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
{ // 虚拟 create 方法
|
{ // 虚拟 create 方法
|
||||||
@@ -555,52 +568,17 @@ public interface Creator<T> {
|
|||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
final byte[] bytes = cw.toByteArray();
|
|
||||||
final boolean ispub = Modifier.isPublic(constructor.getModifiers());
|
|
||||||
Class<?> resultClazz = null;
|
|
||||||
if (loader instanceof URLClassLoader && !ispub) {
|
|
||||||
try {
|
|
||||||
final URLClassLoader urlLoader = (URLClassLoader) loader;
|
|
||||||
final URL url = new URL(
|
|
||||||
"memclass", "localhost", -1, "/" + newDynName.replace('/', '.') + "/", new URLStreamHandler() {
|
|
||||||
@Override
|
|
||||||
protected URLConnection openConnection(URL u) throws IOException {
|
|
||||||
return new URLConnection(u) {
|
|
||||||
@Override
|
|
||||||
public void connect() throws IOException {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
byte[] bytes = cw.toByteArray();
|
||||||
public InputStream getInputStream() throws IOException {
|
|
||||||
return new ByteArrayInputStream(bytes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Method addURLMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
|
||||||
addURLMethod.setAccessible(true);
|
|
||||||
addURLMethod.invoke(urlLoader, url);
|
|
||||||
resultClazz = urlLoader.loadClass(newDynName.replace('/', '.'));
|
|
||||||
} catch (Throwable t) { // 异常无需理会, 使用下一种loader方式
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ispub && resultClazz == null) {
|
|
||||||
throw new RedkaleException(
|
|
||||||
"[" + clazz + "] have no public or ConstructorParameters-Annotation constructor.");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (resultClazz == null) {
|
Class newClazz = new ClassLoader(loader) {
|
||||||
resultClazz = new ClassLoader(loader) {
|
public final Class<?> loadClass(String name, byte[] b) {
|
||||||
public final Class<?> loadClass(String name, byte[] b) {
|
return defineClass(name, b, 0, b.length);
|
||||||
return defineClass(name, b, 0, b.length);
|
}
|
||||||
}
|
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, newClazz);
|
||||||
}
|
RedkaleClassLoader.putReflectionDeclaredConstructors(newClazz, newDynName.replace('/', '.'));
|
||||||
RedkaleClassLoader.putDynClass(newDynName.replace('/', '.'), bytes, resultClazz);
|
return (Creator) newClazz.getDeclaredConstructor().newInstance();
|
||||||
RedkaleClassLoader.putReflectionDeclaredConstructors(resultClazz, newDynName.replace('/', '.'));
|
|
||||||
return (Creator) resultClazz.getDeclaredConstructor().newInstance();
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new RedkaleException(ex);
|
throw new RedkaleException(ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class SncpSleepTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
|
Creator.create(List.class);
|
||||||
System.out.println("------------------- 并发调用 -----------------------------------");
|
System.out.println("------------------- 并发调用 -----------------------------------");
|
||||||
final Application application = Application.create(true);
|
final Application application = Application.create(true);
|
||||||
final ExecutorService workExecutor = WorkThread.createWorkExecutor(10, "Thread-Work-%s");
|
final ExecutorService workExecutor = WorkThread.createWorkExecutor(10, "Thread-Work-%s");
|
||||||
|
|||||||
@@ -36,17 +36,17 @@ public class DynActionTestService_change extends SncpActionServlet {
|
|||||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||||
Convert<Reader, Writer> convert = request.getConvert();
|
Convert<Reader, Writer> convert = request.getConvert();
|
||||||
Reader in = request.getReader();
|
Reader in = request.getReader();
|
||||||
DynActionTestService_change_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
DynSncpActionParamBean_TestService_change bean = convert.convertFrom(paramComposeBeanType, in);
|
||||||
TestService serviceObj = (TestService) service();
|
TestService serviceObj = (TestService) service();
|
||||||
Object rs = serviceObj.change(bean.arg1, bean.arg2, bean.arg3);
|
Object rs = serviceObj.change(bean.arg1, bean.arg2, bean.arg3);
|
||||||
response.finish(boolean.class, rs);
|
response.finish(boolean.class, rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DynActionTestService_change_paramBean {
|
public static class DynSncpActionParamBean_TestService_change {
|
||||||
|
|
||||||
public DynActionTestService_change_paramBean() {}
|
public DynSncpActionParamBean_TestService_change() {}
|
||||||
|
|
||||||
public DynActionTestService_change_paramBean(Object[] params) {
|
public DynSncpActionParamBean_TestService_change(Object[] params) {
|
||||||
this.arg1 = (TestBean) params[0];
|
this.arg1 = (TestBean) params[0];
|
||||||
this.arg2 = (String) params[1];
|
this.arg2 = (String) params[1];
|
||||||
this.arg3 = (int) params[2];
|
this.arg3 = (int) params[2];
|
||||||
|
|||||||
@@ -37,17 +37,17 @@ public class DynActionTestService_changeName extends SncpActionServlet {
|
|||||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||||
Convert<Reader, Writer> convert = request.getConvert();
|
Convert<Reader, Writer> convert = request.getConvert();
|
||||||
Reader in = request.getReader();
|
Reader in = request.getReader();
|
||||||
DynActionTestService_changeName_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
DynSncpActionParamBean_TestService_changeName bean = convert.convertFrom(paramComposeBeanType, in);
|
||||||
TestService serviceObj = (TestService) service();
|
TestService serviceObj = (TestService) service();
|
||||||
CompletableFuture future = serviceObj.changeName(bean.arg1, bean.arg2, bean.arg3);
|
CompletableFuture future = serviceObj.changeName(bean.arg1, bean.arg2, bean.arg3);
|
||||||
response.finishFuture(paramHandlerResultType, future);
|
response.finishFuture(paramHandlerType, future);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DynActionTestService_changeName_paramBean {
|
public static class DynSncpActionParamBean_TestService_changeName {
|
||||||
|
|
||||||
public DynActionTestService_changeName_paramBean() {}
|
public DynSncpActionParamBean_TestService_changeName() {}
|
||||||
|
|
||||||
public DynActionTestService_changeName_paramBean(Object[] params) {
|
public DynSncpActionParamBean_TestService_changeName(Object[] params) {
|
||||||
this.arg1 = (TestBean) params[0];
|
this.arg1 = (TestBean) params[0];
|
||||||
this.arg2 = (String) params[1];
|
this.arg2 = (String) params[1];
|
||||||
this.arg3 = (int) params[2];
|
this.arg3 = (int) params[2];
|
||||||
|
|||||||
@@ -36,18 +36,18 @@ public class DynActionTestService_insert extends SncpActionServlet {
|
|||||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||||
Convert<Reader, Writer> convert = request.getConvert();
|
Convert<Reader, Writer> convert = request.getConvert();
|
||||||
Reader in = request.getReader();
|
Reader in = request.getReader();
|
||||||
DynActionTestService_insert_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
DynSncpActionParamBean_TestService_insert bean = convert.convertFrom(paramComposeBeanType, in);
|
||||||
bean.arg0 = response.getParamAsyncHandler();
|
bean.arg0 = response.getParamAsyncHandler();
|
||||||
TestService serviceObj = (TestService) service();
|
TestService serviceObj = (TestService) service();
|
||||||
serviceObj.insert(bean.arg0, bean.arg1, bean.arg2, bean.arg3);
|
serviceObj.insert(bean.arg0, bean.arg1, bean.arg2, bean.arg3);
|
||||||
response.finishVoid();
|
response.finishVoid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DynActionTestService_insert_paramBean {
|
public static class DynSncpActionParamBean_TestService_insert {
|
||||||
|
|
||||||
public DynActionTestService_insert_paramBean() {}
|
public DynSncpActionParamBean_TestService_insert() {}
|
||||||
|
|
||||||
public DynActionTestService_insert_paramBean(Object[] params) {
|
public DynSncpActionParamBean_TestService_insert(Object[] params) {
|
||||||
this.arg0 = (BooleanHandler) params[0];
|
this.arg0 = (BooleanHandler) params[0];
|
||||||
this.arg1 = (TestBean) params[1];
|
this.arg1 = (TestBean) params[1];
|
||||||
this.arg2 = (String) params[2];
|
this.arg2 = (String) params[2];
|
||||||
|
|||||||
@@ -37,18 +37,18 @@ public class DynActionTestService_update extends SncpActionServlet {
|
|||||||
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
public void action(SncpRequest request, SncpResponse response) throws Throwable {
|
||||||
Convert<Reader, Writer> convert = request.getConvert();
|
Convert<Reader, Writer> convert = request.getConvert();
|
||||||
Reader in = request.getReader();
|
Reader in = request.getReader();
|
||||||
DynActionTestService_update_paramBean bean = convert.convertFrom(paramComposeBeanType, in);
|
DynSncpActionParamBean_TestService_update bean = convert.convertFrom(paramComposeBeanType, in);
|
||||||
bean.arg3 = response.getParamAsyncHandler();
|
bean.arg3 = response.getParamAsyncHandler();
|
||||||
TestService serviceObj = (TestService) service();
|
TestService serviceObj = (TestService) service();
|
||||||
serviceObj.update(bean.arg1, bean.arg2, bean.arg3, bean.arg4, bean.arg5, bean.arg6);
|
serviceObj.update(bean.arg1, bean.arg2, bean.arg3, bean.arg4, bean.arg5, bean.arg6);
|
||||||
response.finishVoid();
|
response.finishVoid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DynActionTestService_update_paramBean {
|
public static class DynSncpActionParamBean_TestService_update {
|
||||||
|
|
||||||
public DynActionTestService_update_paramBean() {}
|
public DynSncpActionParamBean_TestService_update() {}
|
||||||
|
|
||||||
public DynActionTestService_update_paramBean(Object[] params) {
|
public DynSncpActionParamBean_TestService_update(Object[] params) {
|
||||||
this.arg1 = (long) params[0];
|
this.arg1 = (long) params[0];
|
||||||
this.arg2 = (short) params[1];
|
this.arg2 = (short) params[1];
|
||||||
this.arg3 = (CompletionHandler) params[2];
|
this.arg3 = (CompletionHandler) params[2];
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ public class CreatorRecord {
|
|||||||
|
|
||||||
public CreatorRecord() {}
|
public CreatorRecord() {}
|
||||||
|
|
||||||
|
public CreatorRecord(Object[] arg) {
|
||||||
|
System.out.println("creat CreatorRecord!");
|
||||||
|
}
|
||||||
|
|
||||||
@ConstructorParameters({"id", "name", "lval", "tval", "bval", "sval", "cval", "fval", "dval"})
|
@ConstructorParameters({"id", "name", "lval", "tval", "bval", "sval", "cval", "fval", "dval"})
|
||||||
public CreatorRecord(
|
public CreatorRecord(
|
||||||
int id, String name, long lval, boolean tval, byte bval, short sval, char cval, float fval, double dval) {
|
int id, String name, long lval, boolean tval, byte bval, short sval, char cval, float fval, double dval) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public class CreatorTest {
|
|||||||
public static void main(String[] args) throws Throwable {
|
public static void main(String[] args) throws Throwable {
|
||||||
CreatorTest test = new CreatorTest();
|
CreatorTest test = new CreatorTest();
|
||||||
test.run1();
|
test.run1();
|
||||||
|
test.run2();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -35,4 +36,10 @@ public class CreatorTest {
|
|||||||
Assertions.assertEquals("ss", record.getName());
|
Assertions.assertEquals("ss", record.getName());
|
||||||
Assertions.assertEquals(json, json2);
|
Assertions.assertEquals(json, json2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run2() throws Throwable {
|
||||||
|
Creator<CreatorRecord> creator = Creator.create(CreatorRecord.class, 1);
|
||||||
|
creator.create(null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user