Open jiankunking opened 1 month ago
@RestController @RequestMapping("/hbdmorder") public class HbdmOrderController { @Resource private HbdmOrderProcessingService hbdmOrderProcessingService; @PostMapping("/receive") public R receiveOrder(@RequestBody @Valid HbdmOrderParam hbdmOrderParam) { return LockUtil.receiveLock(() -> (hbdmOrderProcessingService.receiveOrder(hbdmOrderParam)), hbdmOrderParam.getInvokingSysOrderNo()); } } public static R receiveLock(RFunction function, String invokingSysOrderNo) { return tryLockAndExecute(function, RedisConstants.ORDER_LOCK + invokingSysOrderNo); } @FunctionalInterface public interface RFunction { R execute(); }
By parsing HbdmOrderController # receptiOrder, the following three calls can be obtained
But when parsing the parameter LockUtil.receiveLock, the type obtained is incorrect
The correct type is: com. hair. hbdm. zhilian. service HbdmOrderProcessingService
But what was obtained is: com. hair. hbdm. zhilian. controller. hbdmOrderProcessingService
public void mavenLoad(String mavenProject, String group, String repo) { MavenLauncher launcher = new MavenLauncher(mavenProject, MavenLauncher.SOURCE_TYPE.APP_SOURCE); launcher.getEnvironment().setComplianceLevel(8); launcher.getEnvironment().setNoClasspath(true); launcher.buildModel(); CtModel model = launcher.getModel(); scan(model, group, repo); } /** * 扫描整个项目 * 从controller扫描 * * @param ctModel */ public void scan(CtModel ctModel, String group, String repo) { boolean hasRequestMapping = false; List<CompletableFuture<Void>> futuresList = new ArrayList<>(); // 获取所有带有Controller、RestController注解的类 for (CtType<?> type : ctModel.getAllTypes()) { if (!Util.isController(type)) { continue; } log.info("class: " + type.getQualifiedName()); if (type.isInterface()) { List<CtType> implementationList = listInterfaceImplElement(ctModel, type); if (implementationList.isEmpty()) { continue; } for (CtType<?> implementation : implementationList) { for (CtMethod<?> ctMethod : implementation.getAllMethods()) { if (!isOverridingInterfaceMethod(type, ctMethod)) { continue; } String nextCallPkg = implementation.getPackage().toString(); String nextCallClazz = implementation.getSimpleName(); String nextCallMethod = ctMethod.getSimpleName(); final String traceId = UuidUtil.getUUID(); Node node = Node.newNode(null, null, null, null, nextCallPkg, nextCallClazz, nextCallMethod, group, repo, traceId); nodeService.save(node); CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> findNextCalls(ctModel, nextCallPkg, nextCallClazz, nextCallMethod, paramTypesToMd5(ctMethod.getParameters()), group, repo, traceId), threadPoolTaskExecutor); futuresList.add(completableFuture); } continue; } } else { for (CtMethod<?> ctMethod : type.getAllMethods()) { hasRequestMapping = false; for (CtAnnotation<?> methodAnnotation : ctMethod.getAnnotations()) { if (!Util.isRequestMappingAnnotation(methodAnnotation)) { continue; } hasRequestMapping = true; break; } if (!hasRequestMapping) { continue; } String nextCallPkg = type.getPackage().toString(); String nextCallClazz = type.getSimpleName(); String nextCallMethod = ctMethod.getSimpleName(); final String traceId = UuidUtil.getUUID(); Node node = Node.newNode(null, null, null, null, nextCallPkg, nextCallClazz, nextCallMethod, group, repo, traceId); nodeService.save(node); CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> findNextCalls(ctModel, nextCallPkg, nextCallClazz, nextCallMethod, paramTypesToMd5(ctMethod.getParameters()), group, repo, traceId), threadPoolTaskExecutor); futuresList.add(completableFuture); } } } CompletableFuture[] array = futuresList.toArray(new CompletableFuture[0]); CompletableFuture.allOf(array).join(); } public void findNextCalls(CtModel ctModel, String pkg, String clazz, String method, String paramTypeMd5, String group, String repo, String traceId) { if (ctModel == null) { return; } if (StringUtil.isEmpty(pkg) || StringUtil.isEmpty(clazz) || StringUtil.isEmpty(method)) { return; } ctModel.getElements(new TypeFilter<CtMethod<?>>(CtMethod.class) { @Override public boolean matches(CtMethod<?> ctMethod) { if (!(ctMethod.getParent() instanceof CtClass)) { return false; } // log.info("class: " + ctMethod.getDeclaringType().getQualifiedName() + ",method:" + ctMethod.getSimpleName()); CtClass cz = (CtClass) ctMethod.getParent(); String curClazz = cz.getSimpleName(); String curPkg = null != cz.getPackage() ? cz.getPackage().getQualifiedName() : "-"; if (!pkg.equals(curPkg)) { return false; } if (!clazz.equals(curClazz)) { return false; } if (!method.equals(ctMethod.getSimpleName())) { return false; } // 方便测试时不校验参数MD5值 if (paramTypeMd5.equals("-1")) { return true; } String md5 = paramTypesToMd5(ctMethod.getParameters()); if (!md5.equals(paramTypeMd5)) { return false; } return true; } }).forEach(ctMethod -> { List<CtInvocation<?>> invocations = ctMethod.getElements(new TypeFilter<>(CtInvocation.class)); String qualifiedName; for (CtInvocation<?> invocation : invocations) { if (invocation == null || invocation.getExecutable() == null || invocation.getExecutable().getDeclaringType() == null) { continue; } qualifiedName = invocation.getExecutable().getDeclaringType().getQualifiedName(); String nextCallPkg = null, nextCallClazz = null, nextCallMethod; if (Util.isPackage(qualifiedName)) { if (!Util.isHaierPackage(qualifiedName)) { continue; } } else { if (!(ctMethod.getParent() instanceof CtClass)) { continue; } } CtExecutableReference executable = invocation.getExecutable(); nextCallMethod = executable.getSimpleName(); CtPackageReference packageReference = executable.getDeclaringType().getPackage(); if (executable.getDeclaringType().isInterface()) { // 如果是接口,则查找实现类 List<CtType> implementationList = listInterfaceImplElement(ctModel, executable.getDeclaringType()); if (implementationList.isEmpty()) { nextCallPkg = packageReference.getSimpleName(); nextCallClazz = executable.getDeclaringType().getSimpleName(); Node node = Node.newNode(pkg, clazz, method, invocation.getPosition().toString(), nextCallPkg, nextCallClazz, nextCallMethod, group, repo, traceId); nodeService.save(node); } else { for (CtType implementation : implementationList) { nextCallPkg = implementation.getPackage().toString(); nextCallClazz = implementation.getSimpleName(); nodeService.save(node); // findNextCalls(ctModel, nextCallPkg, nextCallClazz, nextCallMethod, typeReferenceToMd5(executable.getParameters()), group, repo); String nextTypeMd5 = typeReferenceToMd5(executable.getParameters()); if (pkg.equals(nextCallPkg) && clazz.equals(nextCallClazz) && method.equals(nextCallMethod) && paramTypeMd5.equals(nextTypeMd5)) { // 递归调用跳过 continue; } findNextCalls(ctModel, nextCallPkg, nextCallClazz, nextCallMethod, typeReferenceToMd5(executable.getParameters()), group, repo, traceId); continue; } } continue; } else if (executable.getDeclaringType().isEnum()) { continue; } else { packageReference = executable.getDeclaringType().getPackage(); if (packageReference == null || packageReference.getSimpleName().equals("")) { // 1、针对orderService.gvsLockMarketList(orderGvsLockFormList)获取不到包名及类名 // 回溯到类的字段上 // 2、无法适配lambda中的局部变量,比如下面这种 // 针对() -> (hbdmOrderProcessingService.receiveOrder(hbdmOrderParam)), hbdmOrderParam.getInvokingSysOrderNo() // 这种情况idea的时序图插件sequence diagram也是无法识别的,具体可以readme.md List<CtField<?>> ctFields = ctMethod.getParent().getElements(new TypeFilter<CtField<?>>(CtField.class)); if (ctFields.isEmpty()) { continue; } for (CtField<?> ctField : ctFields) { if (!ctField.getSimpleName().equals(qualifiedName)) { continue; } nextCallPkg = ctField.getType().getPackage().getSimpleName(); nextCallClazz = ctField.getType().getSimpleName(); break; } } else { nextCallPkg = packageReference.getSimpleName(); nextCallClazz = executable.getDeclaringType().getSimpleName(); } Node node = Node.newNode(pkg, clazz, method, invocation.getPosition().toString(), nextCallPkg, nextCallClazz, nextCallMethod, group, repo, traceId); nodeService.save(node); String nextTypeMd5 = typeReferenceToMd5(executable.getParameters()); if (pkg.equals(nextCallPkg) && clazz.equals(nextCallClazz) && method.equals(nextCallMethod) && paramTypeMd5.equals(nextTypeMd5)) { // 递归调用跳过 continue; } findNextCalls(ctModel, nextCallPkg, nextCallClazz, nextCallMethod, typeReferenceToMd5(executable.getParameters()), group, repo, traceId); continue; } } }); }
No response
11.1.0
21.0.1
Windows 10 专业版 21H2
Describe the bug
Using code parsed by Spoon
By parsing HbdmOrderController # receptiOrder, the following three calls can be obtained
But when parsing the parameter LockUtil.receiveLock, the type obtained is incorrect
The correct type is: com. hair. hbdm. zhilian. service HbdmOrderProcessingService
But what was obtained is: com. hair. hbdm. zhilian. controller. hbdmOrderProcessingService
Analyzing Logic
Source code you are trying to analyze/transform
No response
Source code for your Spoon processing
No response
Actual output
No response
Expected output
No response
Spoon Version
11.1.0
JVM Version
21.0.1
What operating system are you using?
Windows 10 专业版 21H2