【问题标题】:Proceed with variable arguments with AspectJ继续使用 AspectJ 处理可变参数
【发布时间】:2011-08-30 14:14:00
【问题描述】:

我正在尝试使用 AspectJ 跨应用程序规范化 URI。我正在使用以下代码捕获对传递 java.net.URI 参数的方法的每个调用:

Object around() : execution(* *(..,java.net.URI,..)) {
    for ( Object arg : thisJoinPoint.getArgs() ) {
        if ( arg instanceof URI ) {
            // normalize
        }
    }
    return proceed();
}

但是,由于 URI 是不可变的,我无法将标准化值交换到现有对象中。我需要的是调用新的、规范化的 URI 对象(并且可能传递其他参数不变)。但是,proceed 调用只允许我传递连接点收集的参数。对于可变数量的参数(主要对任何 URI 参数感兴趣,但愿意收集和传递所有参数),是否有任何方法可以实现此目的?

【问题讨论】:

    标签: java aspectj


    【解决方案1】:

    您需要更改建议的签名:

    Object around(Object[] args) : execution(* *(..,java.net.URI,..)) && args(args) {
        for(int i = 0; i < args.length; i++){
            Object arg = args[i];
            if ( arg instanceof URI ) {
                args[i] = normalizeUrI((URI)arg);
            }
        }
        return proceed(args);
    }
    

    更新:不幸的是,上面的代码不起作用。但这应该:

    Object around() throws URISyntaxException : execution(* **.*(..,URI,..)) {
        final Object[] args = thisJoinPoint.getArgs();
        for(int i = 0; i < args.length; i++){
            final Object arg = args[i];
            if ( arg instanceof URI ) {
                args[i] = normalizeUrI((URI)arg);
            }
        }
        try{
            return ((ProceedingJoinPoint)thisJoinPoint).proceed(args);
        } catch(final Throwable e){
            throw new IllegalStateException(e);
        }
    }
    

    【讨论】:

    • 我希望可以使用类似的东西,但是(除非我以某种方式理解/复制了这个错误)我相信 args(args) 将此连接点限制为仅具有单个 Object[] 参数。由于执行部分将其限制为包含至少一个 URI 参数的方法签名,因此此连接点自相矛盾,永远不会找到匹配项。如果我有误解,请纠正我,但我只是试过这个,它没有产生匹配。谢谢。
    • @Adam 你是对的。看到我改变的答案。该建议至少现在得到应用。
    • 这需要一些创意,但看起来应该可以使用——非常感谢!
    • 它看起来应该可以工作,但它似乎没有......非常奇怪的行为:它不会抛出任何异常(因为文档表明它可能会在出现问题时) - - 它只返回空值。使用 Eclipse,我单步执行它并设置断点以确认建议所建议的方法未执行。 /-:
    【解决方案2】:

    下面应该是评论而不是完整的答案,但我有限的代表不允许我发表评论...

    问题中的代码以及 Sean Patrick Floyd 的答案中的代码都不起作用,因为在方法签名模式中只能出现一次通配符“..”。可以在here找到一个简短的解释。

    【讨论】:

      【解决方案3】:

      我知道这是一个老问题,但官方仍未解决​​。我刚看到,所以我来回答一下:

      您提到 URI 是不可变的。所以基本上这是对正确解决方案的提示:拦截对象创建(构造函数调用)并在around() 建议中检查结果。如果没问题,则传递未更改的 URI,否则创建一个新的,修复或规范任何错误。

      假设您有这个应用程序类创建 URI:

      package de.scrum_master.aspectj.sample.uri;
      
      import java.net.URI;
      import java.net.URISyntaxException;
      
      public class URIApp {
          public static void main(String[] args) throws URISyntaxException {
              URI[] uris = {
                  new URI("https://google.com?search=olympics"),
                  new URI("http://yahoo.com/mail/login"),
                  new URI("https://facebook.com/user?name=kriegaex"),
                  new URI("http://stackoverflow.com/questions/123456")
              };
              for (URI uri : uris)
                  System.out.println(uri);
          }
      }
      

      进一步假设我们认为所有具有“http”方案/协议的 URI 都是不安全的,因此是错误的。我们希望通过使用“https”将 URI 替换为另一个 URI 来解决此问题。我们会在一个方面做到这一点:

      package de.scrum_master.aspectj.sample.uri;
      
      import java.net.URI;
      import java.net.URISyntaxException;
      
      public aspect URIFixer {
          pointcut uriCreation() : call(URI.new(..)) && !within(URIFixer);
      
          URI around() throws URISyntaxException : uriCreation() {
              URI result = proceed();
              return isOk(result) ? result : fix(result);
          }
      
          boolean isOk(URI uri) {
              return "https".equals(uri.getScheme());
          }
      
          URI fix(URI uri) throws URISyntaxException {
              return new URI("https", uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment());
          }
      }
      

      我希望这能回答您的问题,尽管为时已晚。我认为我应该在此处记录解决方案,以供可能找到它的其他用户进一步参考。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 1970-01-01
        • 1970-01-01
        • 2019-09-07
        相关资源
        最近更新 更多