Java - 创建具有特定名称的匿名异常子类
Java - Create anonymous Exception subclass with a certain name
我们使用 Fabric / Crashlytics 将非崩溃问题发送到他们的服务器,然后检查日志和堆栈跟踪。
不幸的是,Crashlytics API 需要针对不同的问题类型使用不同的 Exception subclass 实例。 (在 iOS SDK 中,您可以简单地使用一个字符串来表示不同的问题类型,但在 Android 版本中,您不能)。
public static void craslyticsRecordError(String issueType, String errorMsg)
{
Exception e = new Exception(issueType + "-" + errorMsg);
Crashlytics.logException(e);
}
现在我们有很多不同的问题类型,我们也在运行时动态定义它们(从字符串部分构建在一起)。所以问题是,是否可以使用一些 Java Vodoo / Hacks(反思?)在运行时创建一个具有特定名称的子 class(我们用作问题类型的字符串的名称) 并从中创建实例。
这有可能吗?
我现在正在摆弄 ByteBuddy,试图让它工作 - 但我一直坚持让我的动态 class 正确调用 superclass 构造函数。另外,我不太确定以后是否可以转换为 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'
我仍然面临与以前相同的运行时异常。
默认情况下,Byte Buddy 会复制其超类 class 的构造函数。在您的情况下,它会复制所有 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);
我们使用 Fabric / Crashlytics 将非崩溃问题发送到他们的服务器,然后检查日志和堆栈跟踪。
不幸的是,Crashlytics API 需要针对不同的问题类型使用不同的 Exception subclass 实例。 (在 iOS SDK 中,您可以简单地使用一个字符串来表示不同的问题类型,但在 Android 版本中,您不能)。
public static void craslyticsRecordError(String issueType, String errorMsg)
{
Exception e = new Exception(issueType + "-" + errorMsg);
Crashlytics.logException(e);
}
现在我们有很多不同的问题类型,我们也在运行时动态定义它们(从字符串部分构建在一起)。所以问题是,是否可以使用一些 Java Vodoo / Hacks(反思?)在运行时创建一个具有特定名称的子 class(我们用作问题类型的字符串的名称) 并从中创建实例。
这有可能吗?
我现在正在摆弄 ByteBuddy,试图让它工作 - 但我一直坚持让我的动态 class 正确调用 superclass 构造函数。另外,我不太确定以后是否可以转换为 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'
我仍然面临与以前相同的运行时异常。
默认情况下,Byte Buddy 会复制其超类 class 的构造函数。在您的情况下,它会复制所有 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);