This commit is contained in:
@@ -12,8 +12,10 @@ import java.io.IOException;
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
*
|
||||
* @deprecated
|
||||
* @author zhangjx
|
||||
*/
|
||||
@Deprecated
|
||||
public class DefaultRestServlet extends RestHttpServlet<Object> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,9 +10,11 @@ import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 配合 HttpServlet 使用。
|
||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。
|
||||
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。
|
||||
* 配合 HttpServlet 使用。 <br>
|
||||
* 当标记为 @HttpCacheable 的方法使用response.finish的参数将被缓存一段时间(默认值 seconds=15秒)。 <br>
|
||||
* 通常情况下 @HttpCacheable 需要与 @AuthIgnore 一起使用,没有标记@AuthIgnore的方法一般输出的结果与当前用户信息有关。 <br>
|
||||
* <p>
|
||||
* 注意: 不能标记在HttpServlet类中已有的方法(如: execute/preExecute/authenticate)
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
|
||||
@@ -359,6 +359,32 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将CompletableFuture的结果对象以JSON格式输出
|
||||
*
|
||||
* @param convert 指定的JsonConvert
|
||||
* @param type 指定的类型
|
||||
* @param future 输出对象的句柄
|
||||
*/
|
||||
public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future) {
|
||||
future.whenComplete((v, e) -> {
|
||||
if (e != null) {
|
||||
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
|
||||
finish(500, null);
|
||||
return;
|
||||
}
|
||||
if (v instanceof CharSequence) {
|
||||
finish(v.toString());
|
||||
} else if (v instanceof HttpResult) {
|
||||
finishJson(convert, (HttpResult) v);
|
||||
} else if (v instanceof org.redkale.service.RetResult) {
|
||||
finishJson(convert, (org.redkale.service.RetResult) v);
|
||||
} else {
|
||||
finishJson(convert, type, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将HttpResult的结果对象以JSON格式输出
|
||||
*
|
||||
@@ -397,30 +423,6 @@ public class HttpResponse extends Response<HttpContext, HttpRequest> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将CompletableFuture的结果对象以JSON格式输出
|
||||
*
|
||||
* @param convert 指定的JsonConvert
|
||||
* @param type 指定的类型
|
||||
* @param future 输出对象的句柄
|
||||
*/
|
||||
public void finishJson(final JsonConvert convert, final Type type, final CompletableFuture future) {
|
||||
future.whenComplete((v, e) -> {
|
||||
if (e != null) {
|
||||
context.getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + request, e);
|
||||
finish(500, null);
|
||||
return;
|
||||
}
|
||||
if (v instanceof CharSequence) {
|
||||
finish(v.toString());
|
||||
} else if (v instanceof org.redkale.service.RetResult) {
|
||||
finishJson(convert, (org.redkale.service.RetResult) v);
|
||||
} else {
|
||||
finishJson(convert, type, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定字符串以响应结果输出
|
||||
*
|
||||
|
||||
@@ -111,8 +111,6 @@ public final class Rest {
|
||||
if (!java.lang.reflect.Modifier.isPublic(mod)) return null;
|
||||
if (java.lang.reflect.Modifier.isAbstract(mod)) return null;
|
||||
|
||||
final java.lang.reflect.Type futureRestOutputType = new TypeToken<CompletableFuture<RestOutput>>() {
|
||||
}.getType();
|
||||
final String serviceDesc = Type.getDescriptor(serviceType);
|
||||
final String webServletDesc = Type.getDescriptor(WebServlet.class);
|
||||
final String reqDesc = Type.getDescriptor(HttpRequest.class);
|
||||
@@ -120,7 +118,7 @@ public final class Rest {
|
||||
final String retDesc = Type.getDescriptor(RetResult.class);
|
||||
final String futureDesc = Type.getDescriptor(CompletableFuture.class);
|
||||
final String flipperDesc = Type.getDescriptor(Flipper.class);
|
||||
final String restoutputDesc = Type.getDescriptor(RestOutput.class);
|
||||
final String httprsDesc = Type.getDescriptor(HttpResult.class);
|
||||
final String attrDesc = Type.getDescriptor(org.redkale.util.Attribute.class);
|
||||
final String authDesc = Type.getDescriptor(AuthIgnore.class);
|
||||
final String cacheDesc = Type.getDescriptor(HttpCacheable.class);
|
||||
@@ -464,10 +462,10 @@ public final class Rest {
|
||||
mv.visitVarInsn(ASTORE, maxLocals);
|
||||
varInsns.add(new int[]{ALOAD, maxLocals});
|
||||
} else {
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 3);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitLdcInsn(Type.getType(Type.getDescriptor(ptype)));
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "createAsyncHandler", "(Lorg/redkale/net/http/HttpResponse;Ljava/lang/Class;)Lorg/redkale/util/AsyncHandler;", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "createAsyncHandler", "(Ljava/lang/Class;)Lorg/redkale/util/AsyncHandler;", false);
|
||||
mv.visitTypeInsn(CHECKCAST, ptype.getName().replace('.', '/'));
|
||||
mv.visitVarInsn(ASTORE, maxLocals);
|
||||
varInsns.add(new int[]{ALOAD, maxLocals});
|
||||
@@ -945,12 +943,11 @@ public final class Rest {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + retDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
maxLocals++;
|
||||
} else if (RestOutput.class.isAssignableFrom(returnType)) {
|
||||
} else if (HttpResult.class.isAssignableFrom(returnType)) {
|
||||
mv.visitVarInsn(ASTORE, maxLocals);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, 2); //response
|
||||
mv.visitVarInsn(ALOAD, maxLocals);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + restoutputDesc + ")V", false);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finishJson", "(" + httprsDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
maxLocals++;
|
||||
} else if (Number.class.isAssignableFrom(returnType) || CharSequence.class.isAssignableFrom(returnType)) { //returnType == String.class 必须放在前面
|
||||
@@ -961,14 +958,6 @@ public final class Rest {
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, respInternalName, "finish", "(Ljava/lang/String;)V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
maxLocals++;
|
||||
} else if (futureRestOutputType == returnGenericType) {
|
||||
mv.visitVarInsn(ASTORE, maxLocals);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitVarInsn(ALOAD, maxLocals);
|
||||
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "finishJson", "(" + respDesc + futureDesc + ")V", false);
|
||||
mv.visitInsn(RETURN);
|
||||
maxLocals++;
|
||||
} else if (CompletableFuture.class.isAssignableFrom(returnType)) {
|
||||
mv.visitVarInsn(ASTORE, maxLocals);
|
||||
mv.visitVarInsn(ALOAD, 2);//response
|
||||
|
||||
@@ -10,9 +10,9 @@ import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* 只能注解于Service类的方法的String/byte[]参数或参数内的String/byte[]字段
|
||||
* 只能注解于Service类的方法的String/byte[]/JavaBean参数或参数内的String/byte[]/JavaBean字段
|
||||
* <p>
|
||||
* 用于获取HTTP请求端的请求内容UTF-8编码字符串或者 byte[]
|
||||
* 用于获取HTTP请求端的请求内容UTF-8编码字符串、byte[]、JavaBean
|
||||
*
|
||||
* <p>
|
||||
* 详情见: https://redkale.org
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
package org.redkale.net.http;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import static jdk.internal.org.objectweb.asm.Opcodes.*;
|
||||
import org.redkale.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -23,163 +18,4 @@ public abstract class RestHttpServlet<T> extends HttpServlet {
|
||||
|
||||
protected abstract T currentUser(HttpRequest req) throws IOException;
|
||||
|
||||
protected void finishJson(final HttpResponse response, CompletableFuture<RestOutput> future) throws IOException {
|
||||
future.whenComplete((output, e) -> {
|
||||
if (e != null) {
|
||||
response.getContext().getLogger().log(Level.WARNING, "Servlet occur, forece to close channel. request = " + response.getRequest(), e);
|
||||
response.finish(500, null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
finishJson(response, output);
|
||||
} catch (IOException ioe) {
|
||||
response.getContext().getLogger().log(Level.WARNING, "Servlet finish RestOutput occur, forece to close channel. request = " + response.getRequest(), ioe);
|
||||
response.finish(500, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void finishJson(final HttpResponse response, RestOutput output) throws IOException {
|
||||
if (output == null) {
|
||||
response.finishJson(output);
|
||||
return;
|
||||
}
|
||||
if (output.getContentType() != null) response.setContentType(output.getContentType());
|
||||
response.addHeader(output.getHeaders());
|
||||
response.addCookie(output.getCookies());
|
||||
response.setStatus(output.getStatus() < 1 ? 200 : output.getStatus());
|
||||
if (output.getResult() instanceof File) {
|
||||
response.finish((File) output.getResult());
|
||||
} else if (output.getResult() instanceof String) {
|
||||
response.finish((String) output.getResult());
|
||||
} else if (output.getResult() == null) {
|
||||
response.finish(output.getMessage());
|
||||
} else {
|
||||
response.finishJson(output.getResult());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建AsyncHandler实例,将非字符串对象以JSON格式输出,字符串以文本输出 <br>
|
||||
*
|
||||
* 传入的AsyncHandler子类必须是public,且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数。
|
||||
*
|
||||
* @param <H> AsyncHandler泛型
|
||||
* @param response HttpResponse
|
||||
* @param handlerClass Class
|
||||
*
|
||||
* @return AsyncHandler
|
||||
*/
|
||||
protected final <H extends AsyncHandler> H createAsyncHandler(HttpResponse response, final Class<H> handlerClass) {
|
||||
if (handlerClass == null || handlerClass == AsyncHandler.class) return (H) response.createAsyncHandler();
|
||||
Creator<H> creator = creators.get(handlerClass);
|
||||
if (creator == null) {
|
||||
creator = createCreator(handlerClass);
|
||||
creators.put(handlerClass, creator);
|
||||
}
|
||||
return (H) creator.create(response.createAsyncHandler());
|
||||
}
|
||||
|
||||
private static final ConcurrentHashMap<Class, Creator> creators = new ConcurrentHashMap<>();
|
||||
|
||||
private static <H extends AsyncHandler> Creator<H> createCreator(Class<H> handlerClass) {
|
||||
//生成规则与SncpAsyncHandler.Factory 很类似
|
||||
//-------------------------------------------------------------
|
||||
final boolean handlerinterface = handlerClass.isInterface();
|
||||
final String handlerClassName = handlerClass.getName().replace('.', '/');
|
||||
final String handlerName = AsyncHandler.class.getName().replace('.', '/');
|
||||
final String handlerDesc = Type.getDescriptor(AsyncHandler.class);
|
||||
final String newDynName = handlerClass.getName().replace('.', '/') + "_Dync" + AsyncHandler.class.getSimpleName() + "_" + (System.currentTimeMillis() % 10000);
|
||||
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
FieldVisitor fv;
|
||||
AsmMethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, newDynName, null, handlerinterface ? "java/lang/Object" : handlerClassName, handlerinterface ? new String[]{handlerClassName} : new String[]{handlerName});
|
||||
|
||||
{ //handler 属性
|
||||
fv = cw.visitField(ACC_PRIVATE, "handler", handlerDesc, null, null);
|
||||
fv.visitEnd();
|
||||
}
|
||||
{//构造方法
|
||||
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(" + handlerDesc + ")V", null, null));
|
||||
//mv.setDebug(true);
|
||||
{
|
||||
av0 = mv.visitAnnotation("Ljava/beans/ConstructorProperties;", true);
|
||||
{
|
||||
AnnotationVisitor av1 = av0.visitArray("value");
|
||||
av1.visit(null, "handler");
|
||||
av1.visitEnd();
|
||||
}
|
||||
av0.visitEnd();
|
||||
}
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitMethodInsn(INVOKESPECIAL, handlerinterface ? "java/lang/Object" : handlerClassName, "<init>", "()V", false);
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitFieldInsn(PUTFIELD, newDynName, "handler", handlerDesc);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(2, 2);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
for (java.lang.reflect.Method method : handlerClass.getMethods()) { //
|
||||
if ("completed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "completed", Type.getMethodDescriptor(method), null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "completed", "(Ljava/lang/Object;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
} else if ("failed".equals(method.getName()) && method.getParameterCount() == 2) {
|
||||
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, "failed", Type.getMethodDescriptor(method), null, null));
|
||||
mv.visitVarInsn(ALOAD, 0);
|
||||
mv.visitFieldInsn(GETFIELD, newDynName, "handler", handlerDesc);
|
||||
mv.visitVarInsn(ALOAD, 1);
|
||||
mv.visitVarInsn(ALOAD, 2);
|
||||
mv.visitMethodInsn(INVOKEINTERFACE, handlerName, "failed", "(Ljava/lang/Throwable;Ljava/lang/Object;)V", true);
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(3, 3);
|
||||
mv.visitEnd();
|
||||
} else if (handlerinterface || java.lang.reflect.Modifier.isAbstract(method.getModifiers())) {
|
||||
mv = new AsmMethodVisitor(cw.visitMethod(ACC_PUBLIC, method.getName(), Type.getMethodDescriptor(method), null, null));
|
||||
Class returnType = method.getReturnType();
|
||||
if (returnType == void.class) {
|
||||
mv.visitInsn(RETURN);
|
||||
mv.visitMaxs(0, 1);
|
||||
} else if (returnType.isPrimitive()) {
|
||||
mv.visitInsn(ICONST_0);
|
||||
if (returnType == long.class) {
|
||||
mv.visitInsn(LRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == float.class) {
|
||||
mv.visitInsn(FRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else if (returnType == double.class) {
|
||||
mv.visitInsn(DRETURN);
|
||||
mv.visitMaxs(2, 1);
|
||||
} else {
|
||||
mv.visitInsn(IRETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
} else {
|
||||
mv.visitInsn(ACONST_NULL);
|
||||
mv.visitInsn(ARETURN);
|
||||
mv.visitMaxs(1, 1);
|
||||
}
|
||||
mv.visitEnd();
|
||||
}
|
||||
}
|
||||
cw.visitEnd();
|
||||
byte[] bytes = cw.toByteArray();
|
||||
Class<AsyncHandler> newHandlerClazz = (Class<AsyncHandler>) new ClassLoader(handlerClass.getClassLoader()) {
|
||||
public final Class<?> loadClass(String name, byte[] b) {
|
||||
return defineClass(name, b, 0, b.length);
|
||||
}
|
||||
}.loadClass(newDynName.replace('/', '.'), bytes);
|
||||
return (Creator<H>) Creator.create(newHandlerClazz);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user