gpt4 book ai didi

java - 在AspectJ中排除带注释的方法

转载 作者:行者123 更新时间:2023-12-02 02:18:38 26 4
gpt4 key购买 nike

嗨,我想排除注释的方法,这里是代码。

@Aspect
public class ExceptionHandlingAspect {
private static final String TAG = ExceptionHandlingAspect.class.getName();

@Pointcut("execution(* android.mobile.peakgames.net.aspectjandroid.AspectActivity.*(..)) " +
"&& !@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)")
public void exceptionEntryPoint() {
}

@AfterThrowing(pointcut = "exceptionEntryPoint()", throwing = "throwable")
public void exceptionMethod(JoinPoint joinPoint, Throwable throwable) {
Log.e(TAG, "Exception caught : " + throwable + " on method : " + joinPoint.getSignature());
if (joinPoint.getTarget() instanceof Activity) {
if (throwable instanceof AuthenticationException) {
new AlertDialog.Builder((Context) joinPoint.getTarget())
.setTitle("Authentication Error")
.setMessage("You are not authenticated")
.show();
} else {
new AlertDialog.Builder((Context) joinPoint.getTarget())
.setTitle("Error")
.setMessage("Error occurred at : " + joinPoint.getSignature() + " " +
"Exception : " + throwable)
.show();
}
}
}

@Around(value = "exceptionEntryPoint()")
public Object exceptionAroundMethod(ProceedingJoinPoint joinPoint) {
try {
return joinPoint.proceed();
} catch (Throwable ignored) {
}
return null;
}
}


排除任何用 NoTryCatch注释的方法

上面的代码确实排除了用NoTryCatch注释的方法,但是当该方法被异常调用时,它将终止下一个方法的执行。例如

@NoTryCatch
void test(){throws NullPointor..}


现在我依次调用方法

test()
test1()


test1()无法运行。

如果删除 !@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch),则test1()运行

最佳答案

当然,如果您忽略test1()中引发的异常(即让其升级),则test()不会运行。由于存在未处理的异常,因此永远不会调用下一个方法。我认为这正是您要设计的方面。您为什么期望不同的行为?如果您确实还有其他期望,请在评论中进行说明,然后在编辑答案的过程中向您展示。



OP发表评论后更新:

好吧,您在这里遇到了一个自制的问题:如果方法void caller()调用@NoTryCatch void callee(),则按照设计,当然不会处理callee()中的异常。相反,它会升级到未注释的caller(),因此方面将在那里处理它。调用方如何知道被调用方的某个方面忽略了该异常?或对此如何知道?当将控制权返回给调用方时,被调用方的控制流已经结束。

异常处理的概念至少非常棘手。我什至认为这是有问题的,因为调用链的最内层元素确定所有外层元素都应忽略异常。通常,异常处理是另一种方式。调用者确定如何处理被调用者引发的异常,而不是被调用者本身。因此,我建议您更改您的异常处理概念。

话虽如此,我将向您展示我所说的确实在您的应用程序中发生了一点点MCVE。因为我不是Android开发人员,并且希望它可以在任何Java SE机器上运行,所以我使用模型模拟了Android API的相关部分,例如:

Android API实体模型:

package android.content;

public class Context {}


package android.app;

import android.content.Context;

public class Activity extends Context {}


这只是通过登录到控制台来模拟警报对话框。

package android.app;

import android.content.Context;

public class AlertDialog {
public AlertDialog() {}

public static class Builder {
private String title;
private String message;

public Builder(Context target) {}

public Builder setTitle(String title) {
this.title = title;
return this;
}

public Builder setMessage(String message) {
this.message = message;
return this;
}

public void show() {
System.out.println("ALERT DIALOG: " + title + " -> " + message);
}
}
}


package org.apache.http.auth;

public class AuthenticationException extends Exception {
private static final long serialVersionUID = 1L;

public AuthenticationException(String message) {
super(message);
}
}


标记注释:

package android.mobile.peakgames.net.aspectjandroid.exception;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;

@Retention(RUNTIME)
public @interface NoTryCatch {}


驱动程序应用程序:

package android.mobile.peakgames.net.aspectjandroid;

import org.apache.http.auth.AuthenticationException;

import android.app.Activity;
import android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch;

public class AspectActivity extends Activity {
public String doSomething() {
System.out.println("Doing something");
return "something";
}

@NoTryCatch
public String doSomethingElse() {
System.out.println("Doing something else");
throw new RuntimeException("oops");
}

public String doSomethingFancy() throws AuthenticationException {
System.out.println("Doing something fancy");
throw new AuthenticationException("uh-oh");
}

public void run() throws AuthenticationException {
doSomething();
doSomethingElse();
doSomethingFancy();
}

public static void main(String[] args) throws AuthenticationException {
new AspectActivity().run();
}
}


OP的方面略有优化:

基本上,这是您的方面经过一些优化:


您将错误处理逻辑分为两个建议,一个为“建议”,另一个为“抛出后”。这使得遵循实际的控制流程有些困难,因为在一个建议中您记录了错误,而只是后来又捕获并忽略了另一个建议中的相同错误。因此,我决定将日志记录放到“周围”建议的“捕获”块中,以使发生的事情更加清楚。
原始切入点仅针对类 AspectActivity中的方法。因此,很明显,连接点的目标始终是 Activity,因此始终是 Context。将 target()绑定到advice参数更加清晰,类型安全,并且摆脱了丑陋的强制转换和 instanceof
我将切入点一分为二,因为我们可以在迭代2的后面再使用它们,请参见下文。


package de.scrum_master.aspect;

import org.apache.http.auth.AuthenticationException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.mobile.peakgames.net.aspectjandroid.AspectActivity;
import android.util.Log;

@Aspect
public class ExceptionHandlingAspect {
private static final String TAG = ExceptionHandlingAspect.class.getName();

@Pointcut("execution(* *(..)) && target(activity)")
public void methodsOfInterest(AspectActivity activity) {}

@Pointcut("@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)")
public void annotationNoTryCatch() {}

@Around("methodsOfInterest(activity) && !annotationNoTryCatch()")
public Object exceptionAroundMethod(ProceedingJoinPoint thisJoinPoint, AspectActivity activity) {
try {
return thisJoinPoint.proceed();
} catch (Throwable throwable) {
String errorMessage = "Error " + throwable + " in method " + thisJoinPoint.getSignature();
Log.e(TAG, errorMessage);
Builder builder = new AlertDialog.Builder(activity);
if (throwable instanceof AuthenticationException)
builder.setTitle("Authentication Error").setMessage("You are not authenticated").show();
else
builder.setTitle("Error").setMessage(errorMessage).show();
return null;
}
}
}


控制台日志:

Doing something
Doing something else
[de.scrum_master.aspect.ExceptionHandlingAspect] Error java.lang.RuntimeException: oops in method void android.mobile.peakgames.net.aspectjandroid.AspectActivity.run()
ALERT DIALOG: Error -> Error java.lang.RuntimeException: oops in method void android.mobile.peakgames.net.aspectjandroid.AspectActivity.run()


日志清楚地显示


注释的方法 doSomethingElse()已执行,并且错误未在那里处理,
但是调用方法 run()而是触发建议,因此在那里处理了错误。
即使您也注释了 run(),也会在 main(..)中处理该错误。


那么,您需要怎么做才能避免注释整个呼叫链?只有一种方法-非常丑陋-手动记账,即您的方面需要记住以前忽略的异常实例,因为相应的错误处理建议从未针对该异常运行过。

因此,您需要像这样更改您的方面(忽略手动尝试捕获等创建的多线程和嵌套异常等问题,以免使其变得更加复杂):

方面,迭代2:

package de.scrum_master.aspect;

import java.util.HashSet;
import java.util.Set;

import org.apache.http.auth.AuthenticationException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.mobile.peakgames.net.aspectjandroid.AspectActivity;
import android.util.Log;

@Aspect
public class ExceptionHandlingAspect {
private static final String TAG = ExceptionHandlingAspect.class.getName();

private Set<Throwable> ignoredErrors = new HashSet<>();

@Pointcut("execution(* *(..)) && target(activity)")
public void methodsOfInterest(AspectActivity activity) {}

@Pointcut("@annotation(android.mobile.peakgames.net.aspectjandroid.exception.NoTryCatch)")
public void annotationNoTryCatch() {}

@Around("methodsOfInterest(activity) && !annotationNoTryCatch()")
public Object exceptionAroundMethod(ProceedingJoinPoint thisJoinPoint, AspectActivity activity) throws Throwable {
try {
return thisJoinPoint.proceed();
} catch (Throwable throwable) {
if (ignoredErrors.contains(throwable))
throw throwable;
String errorMessage = "Error " + throwable + " in method " + thisJoinPoint.getSignature();
Log.e(TAG, errorMessage);
Builder builder = new AlertDialog.Builder(activity);
if (throwable instanceof AuthenticationException)
builder.setTitle("Authentication Error").setMessage("You are not authenticated").show();
else
builder.setTitle("Error").setMessage(errorMessage).show();
return null;
}
}

@AfterThrowing(value = "methodsOfInterest(activity) && annotationNoTryCatch()", throwing = "throwable")
public void ignoreExceptions(JoinPoint thisJoinPoint, AspectActivity activity, Throwable throwable) {
ignoredErrors.add(throwable);
}
}


控制台日志,迭代2:

Doing something
Doing something else
Exception in thread "main" java.lang.RuntimeException: oops
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingElse(AspectActivity.java:17)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody4(AspectActivity.java:27)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody5$advice(AspectActivity.java:34)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run(AspectActivity.java:1)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.main(AspectActivity.java:32)


如您所见,异常现在升级,使您想要的应用程序“崩溃”。

附注: InheritableThreadLocal<Throwable>是您的朋友,如果您希望该方面具有线程安全性。随意询问是否需要它,但不知道我在说什么。

P.P.S .:如果将 @NoTryCatch注释从 doSomethingElse()向下移动到 doSomethingFancy,则日志的变化如下:

Doing something
Doing something else
[de.scrum_master.aspect.ExceptionHandlingAspect] Error java.lang.RuntimeException: oops in method String android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingElse()
ALERT DIALOG: Error -> Error java.lang.RuntimeException: oops in method String android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingElse()
Doing something fancy
Exception in thread "main" org.apache.http.auth.AuthenticationException: uh-oh
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.doSomethingFancy(AspectActivity.java:22)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody4(AspectActivity.java:28)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run_aroundBody5$advice(AspectActivity.java:34)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.run(AspectActivity.java:1)
at android.mobile.peakgames.net.aspectjandroid.AspectActivity.main(AspectActivity.java:32)

关于java - 在AspectJ中排除带注释的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48882522/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com