【问题标题】:Java - Create anonymous Exception subclass with a certain nameJava - 创建具有特定名称的匿名异常子类
【发布时间】:2017-08-17 15:44:38
【问题描述】:

我们使用 Fabric / Crashlytics 将非崩溃问题发送到他们的服务器,然后检查日志和堆栈跟踪。

很遗憾,Crashlytics API 需要针对不同的问题类型使用不同的 Exception 子类实例。 (在 iOS SDK 中,您可以简单地将字符串用于不同的问题类型,但在 Android 版本中,您不能)。

public static void craslyticsRecordError(String issueType, String errorMsg)
{
    Exception e = new Exception(issueType + "-" + errorMsg);
    Crashlytics.logException(e);
}

现在我们有很多不同的问题类型,我们也在运行时动态定义(从字符串部分一起构建)。所以问题是,是否有可能使用一些 Java Vodoo / Hacks(反射?)在运行时创建一个具有特定名称(我们用作问题类型的字符串的名称)的子类,并从中创建和实例化。

这有可能吗?


我现在正在摆弄 ByteBuddy,试图让它工作 - 但我坚持让我的动态类正确调用超类构造函数。此外,我不太确定我是否可以稍后转换为 Exception。


感谢 Rafael Winterhalter,让我更进一步让这件事发挥作用;)我已经完全按照您提供的方式进行了尝试:

public static void craslyticsRecordError(String issueType, String errorMsg)
{
    Class<? extends Exception> dynamicType = new ByteBuddy()
            .subclass(Exception.class)
            .name(issueType)
            .make()
            .load(Fabric.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
            .getLoaded();
    try
    {
        Exception e = dynamicType.getConstructor(String.class).newInstance(errorMsg);

        GameLog.d("[Fabric] Inner Exception: " + e);
        Crashlytics.logException(e);
    }
    catch (Exception e1)
    {
        Exception e = new Exception(issueType + "-" + errorMsg);
        GameLog.d("[Fabric] ERROR ONE");
        Crashlytics.logException(e);
        e1.printStackTrace();
    }
}

现在我正面临这个运行时异常:

java.lang.NoClassDefFoundError: net.bytebuddy.dynamic.loading.NoOpClassFileTransformer
     at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.<init>(ByteArrayClassLoader.java:136)
     at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.of(ByteArrayClassLoader.java:187)
     at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.load(ByteArrayClassLoader.java:212)
     at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$WrappingDispatcher.load(ClassLoadingStrategy.java:285)
     at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:120)
     at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79)
     at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4376)
     at org.utils.Fabric.craslyticsRecordError(Fabric.java:47)
     at android.os.MessageQueue.nativePollOnce(Native Method)
     at android.os.MessageQueue.next(MessageQueue.java:323)
     at android.os.Looper.loop(Looper.java:143)
     at android.app.ActivityThread.main(ActivityThread.java:7224)
     at java.lang.reflect.Method.invoke(Native Method)
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

现在使用此 Android 特定代码后:

Class<? extends Exception> dynamicType = new ByteBuddy()
        .subclass(Exception.class)
        .name(issueType)
        .make()
        .load(Fabric.class.getClassLoader(), AndroidClassLoadingStrategy.Default.WRAPPER)
        .getLoaded();

并使用 Android 特定的 gradle 编译行:

compile 'net.bytebuddy:byte-buddy-android:1.7.3'

我仍然面临与以前相同的运行时异常。

【问题讨论】:

  • 这是您需要的吗? - *.com/questions/17259421/…
  • 这看起来很不错,我目前正在尝试让 ByteBuddy 运行,但我有点坚持让我的动态类调用它的超类的构造函数,请参阅我的编辑。跨度>

标签: java android crashlytics byte-buddy crashlytics-android


【解决方案1】:

默认情况下,Byte Buddy 复制其超类的构造函数。在您的情况下,它会复制所有 Exception 构造函数,您可以生成如下异常:

Class<? extends Exception> dynamicType = new ByteBuddy()
  .subclass(Exception.class)
  .name(issueType)
  .make()
  .load(Fabric.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
  .getLoaded();

 Exception e = dynamicType.getConstructor(String.class).newInstance(errorMsg);

【讨论】:

  • 谢谢!这让我更进一步!你在这里活跃真是太好了!不幸的是,我现在在运行代码时遇到了运行时异常(请参阅上面的编辑)。你知道出了什么问题吗?
  • 您使用的是Android,本例使用byte-buddy-android项目中的AndroidClassLoadingStrategy。
  • 感谢您的提示,我已经更改了它(请参阅编辑),但我仍然面临相同的运行时异常。还有什么想法吗? ;)
  • 你使用的策略和以前一样,你只是通过子类访问默认策略。需要自己实例化android类加载策略。
  • 谢谢,它确实有效。对于构造函数中的“私有目录”,我只是在应用程序的文件目录中使用了一些目录——我希望没关系。我还想用一些代码添加一个特定的方法......但我会摆弄一下 - 如果我不成功,也许会打开另一个问题。到目前为止非常感谢!