【问题标题】:ClassNotFoundException in Aspect when using proguard使用 proguard 时 Aspect 中的 ClassNotFoundException
【发布时间】:2014-07-21 14:46:53
【问题描述】:

当我使用 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();

                .
                .
                .
    }

}

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

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

我们将不胜感激。

【问题讨论】:

  • 我想帮忙,因为我知道 ProGuard 和 AspectJ,但是你的问题是如此的不清楚和自相矛盾,以至于我无法理解你的问题。请编辑问题并更准确地解释。如果你的英语太差,没问题:让代码说话,向我们展示更多代码。
  • 对不起。我编辑了我的问题:)
  • 您的 ProGuard 配置丢失。无论如何,我会调查您的问题,但只是附带说明:请使用更新版本的 AspectJ。 1.6.12 版于 2011 年发布,您已经错过了几个从那时到今天的改进和错误修复的版本。当前版本是 1.8.0。
  • 我将我的 aspectj 更新到 1.8.0 但没有任何改变:(
  • 我没有说升级 AspectJ 后会有什么改变,只是你使用了过时的库。顺便说一句,Java 和 ProGuard 版本也不是最新的。我仍然希望看到您的 ProGuard 配置。您是使用 proguard.conf 还是使用 Maven 插件手动构建?

标签: java proguard aspectj obfuscation


【解决方案1】:

好的,这很棘手,但最后我能够重现存储在thisJoinPointStaticPart 中的错误MethodSignature 的问题。我尝试了很多 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 语法,因为这是我觉得更舒服的风格。但是代码与您的示例足够相似,可以轻松转换。也许您需要为 ProGuard 增加一些用于 @AspectJ 注释的 keep 子句,但这应该是微不足道的。
  • Git 存储库有两个标签,single_project(一个包含所有内容的 Maven 模块的最新提交)和 multi_project(具有三个 Maven 模块的旧提交,一个用于主应用程序,一个用于注释,一个用于方面)。如果您愿意,可以比较这两种变体。

享受吧!我希望它能解决你的问题。 :-)

更新:我忘了提及如何准确重现问题:只需删除 &lt;option&gt;-adaptclassstrings&lt;/option&gt;,重新构建并再次运行程序:

(...)
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

【讨论】:

  • 感谢 kriegaex :) 你太棒了 :) 它就像一个魅力 ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-19
  • 2017-01-09
  • 2021-11-22
  • 1970-01-01
  • 1970-01-01
  • 2021-07-14
  • 1970-01-01
相关资源
最近更新 更多