Skip to content

Commit 543a5e7

Browse files
committed
implement actframework#406
1 parent 34b3a05 commit 543a5e7

10 files changed

Lines changed: 150 additions & 22 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
**1.4.15**
44

5+
*
56
* Add built-in API to report app version and act version #405
67
* Update riotjs version and add riot-route.js #404
78

src/main/java/act/cli/CliContext.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,13 @@ public static ParsingContext finish() {
161161
}
162162

163163
public static final String ATTR_PWD = "__act_pwd__";
164-
public static final String ATTR_METHOD = "__act_method__";
164+
/**
165+
* Used to cache current method to context.
166+
*
167+
* This is deprecated. Please use {@link ActContext#ATTR_CUR_METHOD} instead
168+
*/
169+
@Deprecated
170+
public static final String ATTR_METHOD = ActContext.ATTR_CUR_METHOD;
165171

166172
private static final ContextLocal<CliContext> _local = $.contextLocal();
167173

src/main/java/act/cli/bytecode/ReflectedCommandExecutor.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import act.inject.param.ParamValueLoaderManager;
3232
import act.job.AppJobManager;
3333
import act.job.TrackableWorker;
34+
import act.util.ActContext;
3435
import act.util.Async;
3536
import act.util.ProgressGauge;
3637
import com.esotericsoftware.reflectasm.MethodAccess;
@@ -94,7 +95,7 @@ public ReflectedCommandExecutor(CommandMethodMetaInfo methodMetaInfo, App app) {
9495

9596
@Override
9697
public Object execute(CliContext context) {
97-
context.attribute(CliContext.ATTR_METHOD, method);
98+
context.attribute(ActContext.ATTR_CUR_METHOD, method);
9899
if (null != pattern) {
99100
context.pattern(pattern);
100101
}

src/main/java/act/handler/builtin/controller/impl/ReflectedHandlerInvoker.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ public Result handle(final ActionContext context) throws Exception {
284284
}
285285

286286
context.attribute("reflected_handler", this);
287+
context.attribute(ActContext.ATTR_CUR_METHOD, method);
287288
if (null != templateContext && context.state().isHandling()) {
288289
context.templateContext(templateContext);
289290
}

src/main/java/act/inject/param/CliContextParamLoader.java

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@
2020
* #L%
2121
*/
2222

23+
import act.Act;
2324
import act.app.ActionContext;
2425
import act.app.App;
2526
import act.cli.CliContext;
2627
import act.cli.Optional;
2728
import act.cli.Required;
2829
import act.cli.meta.CommandMethodMetaInfo;
2930
import act.cli.util.CommandLineParser;
31+
import act.util.ActContext;
3032
import org.osgl.$;
33+
import org.osgl.http.H;
3134
import org.osgl.inject.BeanSpec;
3235
import org.osgl.inject.util.AnnotationUtil;
3336
import org.osgl.mvc.annotation.Resolve;
@@ -41,6 +44,7 @@
4144
import java.lang.reflect.Type;
4245
import java.util.ArrayList;
4346
import java.util.List;
47+
import java.util.Set;
4448
import java.util.concurrent.ConcurrentHashMap;
4549
import java.util.concurrent.ConcurrentMap;
4650

@@ -66,7 +70,41 @@ public CliContext.ParsingContext buildParsingContext(Class commander, Method met
6670
classRegistry.putIfAbsent(commander, loader);
6771
}
6872
$.Var<Boolean> boolBag = $.var();
69-
ParamValueLoader[] loaders = findMethodParamLoaders(method, commander, boolBag);
73+
// create a pseudo ctx as we do not have one here
74+
// the ctx is just a way to pass the method info
75+
ActContext ctx = new ActContext.Base<ActContext.Base>(Act.app()) {
76+
@Override
77+
public Base accept(H.Format fmt) {
78+
return null;
79+
}
80+
81+
@Override
82+
public H.Format accept() {
83+
return null;
84+
}
85+
86+
@Override
87+
public String methodPath() {
88+
return null;
89+
}
90+
91+
@Override
92+
public Set<String> paramKeys() {
93+
return null;
94+
}
95+
96+
@Override
97+
public String paramVal(String key) {
98+
return null;
99+
}
100+
101+
@Override
102+
public String[] paramVals(String key) {
103+
return new String[0];
104+
}
105+
};
106+
ctx.attribute(ActContext.ATTR_CUR_METHOD, method);
107+
ParamValueLoader[] loaders = findMethodParamLoaders(method, commander, ctx, boolBag);
70108
methodRegistry.putIfAbsent(method, loaders);
71109
methodValidationConstraintLookup.put(method, boolBag.get());
72110
return CliContext.ParsingContextBuilder.finish();

src/main/java/act/inject/param/ParamValueLoader.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@
2828
*/
2929
public interface ParamValueLoader {
3030

31+
ParamValueLoader NIL = new ParamValueLoader() {
32+
@Override
33+
public Object load(Object bean, ActContext<?> context, boolean noDefaultValue) {
34+
return null;
35+
}
36+
37+
@Override
38+
public String bindName() {
39+
return null;
40+
}
41+
};
42+
3143
/**
3244
* Provide the value for a parameter from current execution context.
3345
*

src/main/java/act/inject/param/ParamValueLoaderService.java

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ public Object loadHostBean(Class beanClass, ActContext<?> ctx) {
152152
return loader.load(null, ctx, false);
153153
}
154154

155-
public ParamValueLoader[] methodParamLoaders(Object host, Method method) {
155+
public ParamValueLoader[] methodParamLoaders(Object host, Method method, ActContext ctx) {
156156
ParamValueLoader[] loaders = methodRegistry.get(method);
157157
if (null == loaders) {
158158
$.Var<Boolean> boolBag = $.var(Boolean.FALSE);
159159
Class hostClass = null == host ? null : host.getClass();
160-
ParamValueLoader[] newLoaders = findMethodParamLoaders(method, hostClass, boolBag);
160+
ParamValueLoader[] newLoaders = findMethodParamLoaders(method, hostClass, ctx, boolBag);
161161
loaders = methodRegistry.putIfAbsent(method, newLoaders);
162162
if (null == loaders) {
163163
loaders = newLoaders;
@@ -174,7 +174,7 @@ public ParamValueLoader[] methodParamLoaders(Object host, Method method) {
174174

175175
public Object[] loadMethodParams(Object host, Method method, ActContext ctx) {
176176
try {
177-
ParamValueLoader[] loaders = methodParamLoaders(host, method);
177+
ParamValueLoader[] loaders = methodParamLoaders(host, method, ctx);
178178
Boolean hasValidationConstraint = methodValidationConstraintLookup.get(method);
179179
int sz = loaders.length;
180180
Object[] params = new Object[sz];
@@ -290,7 +290,7 @@ private <T> Map<Field, ParamValueLoader> fieldLoaders(Class<T> beanClass) {
290290
continue;
291291
}
292292
BeanSpec spec = BeanSpec.of(field, injector);
293-
ParamValueLoader loader = paramValueLoaderOf(spec);
293+
ParamValueLoader loader = paramValueLoaderOf(spec, null);
294294
boolean provided = (loader instanceof ProvidedValueLoader);
295295
if (null != loader && !provided) {
296296
newFieldLoaders.put(field, loader);
@@ -304,7 +304,9 @@ private <T> Map<Field, ParamValueLoader> fieldLoaders(Class<T> beanClass) {
304304
return fieldLoaders;
305305
}
306306

307-
protected ParamValueLoader[] findMethodParamLoaders(Method method, Class host, $.Var<Boolean> hasValidationConstraint) {
307+
protected ParamValueLoader[] findMethodParamLoaders(
308+
Method method, Class host,
309+
ActContext ctx, $.Var<Boolean> hasValidationConstraint) {
308310
Type[] types = method.getGenericParameterTypes();
309311
int sz = types.length;
310312
if (0 == sz) {
@@ -328,7 +330,7 @@ protected ParamValueLoader[] findMethodParamLoaders(Method method, Class host, $
328330
if (hasValidationConstraint(spec)) {
329331
hasValidationConstraint.set(true);
330332
}
331-
ParamValueLoader loader = paramValueLoaderOf(spec);
333+
ParamValueLoader loader = paramValueLoaderOf(spec, ctx);
332334
if (null == loader) {
333335
throw new UnexpectedException("Cannot find param value loader for param: " + spec);
334336
}
@@ -337,16 +339,18 @@ protected ParamValueLoader[] findMethodParamLoaders(Method method, Class host, $
337339
return loaders;
338340
}
339341

340-
private ParamValueLoader paramValueLoaderOf(BeanSpec spec) {
341-
return paramValueLoaderOf(spec, null);
342+
private ParamValueLoader paramValueLoaderOf(BeanSpec spec, ActContext ctx) {
343+
return paramValueLoaderOf(spec, null, ctx);
342344
}
343345

344-
private ParamValueLoader paramValueLoaderOf(BeanSpec spec, String bindName) {
346+
private ParamValueLoader paramValueLoaderOf(BeanSpec spec, String bindName, ActContext ctx) {
345347
Class<?> rawType = spec.rawType();
346348
if (Result.class.isAssignableFrom(rawType)) {
347349
return RESULT_LOADER;
348350
} else if (Throwable.class.isAssignableFrom(rawType)) {
349351
return new ThrowableLoader((Class<? extends Throwable>)rawType);
352+
} else if (Annotation.class.isAssignableFrom(rawType)) {
353+
return findHandlerMethodAnnotation((Class<? extends Annotation>) rawType, ctx);
350354
}
351355
Type type = spec.type();
352356
Annotation[] annotations = spec.allAnnotations();
@@ -366,6 +370,60 @@ private ParamValueLoader paramValueLoaderOf(BeanSpec spec, String bindName) {
366370
return loader;
367371
}
368372

373+
/**
374+
* Returns a `ParamValueLoader` that load annotation from:
375+
* * the handler method
376+
* * the current method (might be a intercepter method)
377+
*
378+
* @param annoType the annotation type
379+
* @param ctx the current {@link ActContext}
380+
* @return a `ParamValueLoader` instance
381+
*/
382+
private ParamValueLoader findHandlerMethodAnnotation(final Class<? extends Annotation> annoType, ActContext<?> ctx) {
383+
if (null == ctx) {
384+
return ParamValueLoader.NIL;
385+
}
386+
return new ParamValueLoader() {
387+
@Override
388+
public Object load(Object bean, ActContext<?> ctx, boolean noDefaultValue) {
389+
String methodPath = ctx.methodPath();
390+
Method curMethod = ctx.attribute(ActContext.ATTR_CUR_METHOD);
391+
boolean methodIsCurrent = false;
392+
393+
Annotation anno = null;
394+
if (S.notBlank(methodPath)) {
395+
String methodName = S.afterLast(methodPath, ".");
396+
Class<?> hostClass = Act.appClassForName(S.beforeLast(methodPath, "."));
397+
Method method = null;
398+
if (S.eq(methodName, curMethod.getName()) && $.eq(hostClass, curMethod.getDeclaringClass())) {
399+
method = curMethod;
400+
methodIsCurrent = true;
401+
} else {
402+
for (Method classMethod : hostClass.getMethods()) {
403+
if (S.eq(methodName, classMethod.getName())) {
404+
method = classMethod;
405+
break;
406+
}
407+
}
408+
}
409+
if (null != method) {
410+
anno = method.getAnnotation(annoType);
411+
}
412+
}
413+
if (null == anno && !methodIsCurrent) {
414+
anno = curMethod.getAnnotation(annoType);
415+
}
416+
return anno;
417+
}
418+
419+
@Override
420+
public String bindName() {
421+
return null;
422+
}
423+
};
424+
}
425+
426+
369427
protected abstract ParamValueLoader findContextSpecificLoader(
370428
String bindName,
371429
Class<?> rawType,

src/main/java/act/job/bytecode/ReflectedJobInvoker.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import act.job.meta.JobClassMetaInfo;
2828
import act.job.meta.JobMethodMetaInfo;
2929
import act.sys.Env;
30+
import act.util.ActContext;
3031
import act.util.ReflectedInvokerHelper;
3132
import com.esotericsoftware.reflectasm.MethodAccess;
3233
import org.osgl.$;
@@ -103,8 +104,10 @@ public Object apply() throws NotAppliedException, $.Break {
103104
if (disabled) {
104105
return null;
105106
}
106-
Object job = jobClassInstance(app);
107-
return invoke(job);
107+
JobContext ctx = JobContext.current();
108+
ctx.attribute(ActContext.ATTR_CUR_METHOD, method);
109+
Object job = jobClassInstance(app, ctx);
110+
return invoke(job, ctx);
108111
}
109112

110113
private Class[] paramTypes() {
@@ -119,25 +122,26 @@ private Class[] paramTypes() {
119122
}
120123

121124

122-
private Object jobClassInstance(App app) {
125+
private Object jobClassInstance(App app, JobContext ctx) {
123126
if (isStatic) {
124127
return null;
125128
}
126129
if (null != singleton) {
127130
return singleton;
128131
}
129-
return null != paramValueLoaderService ? paramValueLoaderService.loadHostBean(jobClass, JobContext.current())
132+
return null != paramValueLoaderService ?
133+
paramValueLoaderService.loadHostBean(jobClass, ctx)
130134
: app.getInstance(jobClass);
131135
}
132136

133-
private Object invoke(Object jobClassInstance) {
134-
Object[] params = params(jobClassInstance);
137+
private Object invoke(Object jobClassInstance, JobContext ctx) {
138+
Object[] params = params(jobClassInstance, ctx);
135139
return null == methodAccess ? $.invokeStatic(method, params) : methodAccess.invoke(jobClassInstance, methodIndex, params);
136140
}
137141

138-
private Object[] params(Object job) {
142+
private Object[] params(Object job, JobContext ctx) {
139143
if (null != paramValueLoaderService) {
140-
return paramValueLoaderService.loadMethodParams(job, method, JobContext.current());
144+
return paramValueLoaderService.loadMethodParams(job, method, ctx);
141145
}
142146
E.illegalStateIf(paramTypes().length > 0, "Cannot invoke job with parameters before app fully started");
143147
return new Object[0];

src/main/java/act/util/ActContext.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
import java.util.*;
4242

4343
public interface ActContext<CTX_TYPE extends ActContext> extends ParamValueProvider {
44+
/**
45+
* Used to store the {@link java.lang.reflect.Method} this context is trying
46+
* to invoke right now. Note the method might be corresponding to the
47+
* {@link #methodPath()} or not if the current method is an interceptor.
48+
*/
49+
String ATTR_CUR_METHOD = "__ctx_cur_method__";
4450
App app();
4551
AppConfig config();
4652
CTX_TYPE accept(H.Format fmt);

src/main/java/act/xio/WebSocketConnectionHandler.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,9 @@ public WebSocketConnectionHandler(ActionMethodMetaInfo methodInfo, WebSocketConn
125125
if (fieldsAndParamsCount == 1) {
126126
singleJsonFieldName = paramSpecs.get(0).name();
127127
}
128-
129-
ParamValueLoader[] loaders = paramLoaderService.methodParamLoaders(host, method);
128+
// todo: do we want to allow inject Annotation type into web socket
129+
// handler method param list?
130+
ParamValueLoader[] loaders = paramLoaderService.methodParamLoaders(host, method, null);
130131
if (loaders.length > 0) {
131132
int realParamCnt = 0;
132133
for (ParamValueLoader loader : loaders) {

0 commit comments

Comments
 (0)