当我用proguard混淆代码时,我的方面类有问题。

我有一个方面可以检测所有带有@Cacheable批注的方法。

这是一个包含@Cacheable注解的示例类

package com.mycompany.user;

public class User {

    @Cacheable(scope="session", uniqueName="userInfo")
    public UserInfo getUserInfo(Long userId) {
       ...
    }
}


这是我的方面代码:

@Aspect
public class CacheMethodResultAspect {
    @Around(
            value = "execution(@com.mycompany.cache.Cacheable * *.*(..))",
            argNames = "proceedingJoinPoint,joinPointStaticPart"
    )
    public Object retrieveResultFromCache(ProceedingJoinPoint proceedingJoinPoint, JoinPoint.StaticPart joinPointStaticPart)
            throws Throwable {

        final CacheScope cacheScope = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod().getAnnotation(Cacheable.class).scope();
        final CacheConstants uniqueName = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod().getAnnotation(Cacheable.class).uniqueName();
        final String methodLine = proceedingJoinPoint.getSignature().getDeclaringTypeName() + "." + proceedingJoinPoint.getSignature().getName()
                + "@" + joinPointStaticPart.getSourceLocation().getLine();

                .
                .
                .
    }

}


当我记录procedingJoinPoint的结果时,它将返回以下行:

execution(UserInfo java.lang.ClassNotFoundException.getUserInfo())


我希望它返回此结果:

execution(UserInfo com.mycompany.user.getUserInfo())


它仅检测方法名称!所以我无法获取此方法的@Cacheable注解!

我不想使用:

-keep class myClassName...


Aspectj版本:1.6.12

Java版本:1.7更新21

proguard版本:4.9

任何帮助将不胜感激。

最佳答案

好的,这很棘手,但是最后我能够用存储在MethodSignature中的错误thisJoinPointStaticPart重现该问题。我尝试了很多ProGuard选项,但最后我发现-adaptclassstrings是缺少的选项。显然,AspectJ使用以字符串编码的类名-也许类似于Class.forName(),我没有检查字节码。

ProGuard Maven插件配置中最重要的部分是这一部分:

<configuration>
    <options>
        <option>-target 1.7</option>
        <option>-adaptclassstrings</option>
        <option>-keepclasseswithmembers public class * { public static void main(java.lang.String[]); }</option>
        <option>-keepattributes *Annotation*</option>
        <option>-keepclassmembernames class * { @de.scrum_master.app.Cacheable *** **(...); }</option>
    </options>
    <libs>
        <lib>${java.home}/lib/rt.jar</lib>
        <!--<lib>${java.home}/lib/jsse.jar</lib>-->
    </libs>
</configuration>


因为完整的说明太大了,无法在此处引用完整的示例代码等,所以我为您创建了一个GitHub project。请在那里检查代码和ProGuard的Maven设置。您可以克隆存储库并调用

mvn install


我为您提供了非常方便的服务,甚至包括一个OneJAR构建步骤,因此构建后您可以调用

java -jar target/aspectj-proguard-1.0-SNAPSHOT.one-jar.jar


从项目目录。输出应如下所示:

User{id=1, info=UserInfo{info='First'}}
User{id=2, info=UserInfo{info='Second'}}
User{id=3, info=UserInfo{info='Third'}}
User{id=4, info=UserInfo{info='Fourth'}}
User{id=5, info=UserInfo{info='Fifth'}}
execution(d de.scrum_master.app.b.getUserInfo(Long))
  Cacheable scope:       session
  Cacheable unique name: userInfo
  Method line:           de.scrum_master.app.b.getUserInfo@27
UserInfo{info='First'}
execution(d de.scrum_master.app.b.getUserInfo(Long))
  Cacheable scope:       session
  Cacheable unique name: userInfo
  Method line:           de.scrum_master.app.b.getUserInfo@27
UserInfo{info='Third'}
execution(d de.scrum_master.app.b.getUserInfo(Long))
  Cacheable scope:       session
  Cacheable unique name: userInfo
  Method line:           de.scrum_master.app.b.getUserInfo@27
UserInfo{info='Fifth'}
execution(d de.scrum_master.app.b.getUserInfo(Long))
  Cacheable scope:       session
  Cacheable unique name: userInfo
  Method line:           de.scrum_master.app.b.getUserInfo@27
null


其他提示:


我使用本机AspectJ语法而不是基于注释的@AspectJ语法,因为这是我更喜欢的风格。但是代码与您的示例足够相似,因此可以轻松转换。也许您需要为@AspectJ批注的ProGuard保留更多的keep子句,但这应该很简单。
Git存储库具有两个标签,single_project(使用一个包含所有内容的Maven模块的最新提交)和multi_project(包含三个Maven模块的较旧提交,一个用于主应用程序,一个用于注释,一个用于方面)。如果愿意,您可以比较两个变体。


请享用!我希望它能解决您的问题。 :-)

更新:我忘了提到如何准确重现该问题:只需删除<option>-adaptclassstrings</option>,重新生成并再次运行该程序:

(...)
User{id=5, info=UserInfo{info='Fifth'}}
execution(ClassNotFoundException java.lang.ClassNotFoundException.getUserInfo(Long))
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at com.simontuffs.onejar.Boot.run(Boot.java:306)
        at com.simontuffs.onejar.Boot.main(Boot.java:159)
Caused by: java.lang.NullPointerException
        at de.scrum_master.a.a.a(Unknown Source)
        at de.scrum_master.app.b.getUserInfo(Unknown Source)
        at de.scrum_master.app.Application.main(Unknown Source)
        ... 6 more

07-28 03:48
查看更多