gpt4 book ai didi

java - JAX-RS 客户端可以抛出自定义异常类型吗?

转载 作者:行者123 更新时间:2023-11-30 06:13:04 25 4
gpt4 key购买 nike

我希望我的服务客户端的使用者能够获得比标准 JAX-RS WebApplicationExceptions 更有意义的异常,这样他们就可以根据 500 异常的原因执行重试或不重试等操作。

我在服务端有一个 ExceptionMapper,它将实际的异常作为返回的异常中的响应实体,如下所示:

public Response toResponse(InternalException ex) {
return Response.status(ex.getStatus)
.entity(ex)
.type(MediaType.APPLICATION_JSON_TYPE)
.build();
}

这似乎有效。问题是,在客户端中,即使我有一个 ClientResponseFilter 从响应中提取 InternalException 并将其抛出,JAX-RS 也会将其包装在 ProcessingException 中,这违背了整个要点!

Testcase: badRequest_clientCall_modeledExceptionThrown took 0.272 sec
Caused an ERROR
Unexpected exception, expected<not.actual.package.InternalException> but was<javax.ws.rs.ProcessingException>
java.lang.Exception: Unexpected exception, expected<not.actual.package.InternalException> but was<javax.ws.rs.ProcessingException>
Caused by: javax.ws.rs.ProcessingException
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:263)
at org.glassfish.jersey.client.JerseyInvocation$3.call(JerseyInvocation.java:709)
<Incredibly secret stuff ommitted>
Caused by: not.actual.package.InternalException

我如何真正让这个客户端抛出正确的异常,而不是将最终输出包装在 try/catch 中(我不想这样做,因为它会使重试逻辑复杂化)?

最佳答案

您可以使用spring或JavaEE的AOP( JaveEE APO example )。使用 @AroundInvoke 来调用您的服务方法。只需在您的服务方法中抛出异常即可。我建议您创建自己的异常,例如 UsernameInvalidExceptionParameterErrorException下面是 JavaEE 的代码示例:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;

import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
import javax.persistence.EntityManager;
import java.io.IOException;
import java.lang.reflect.Field;

@YourExceptionHandler
@Interceptor
public class YourExceptionInterceptor {

@Inject
private Logger logger;

@AroundInvoke
public Object handleException(InvocationContext ctx) {

//logger.debug("hash:{}", System.identityHashCode(this));
Result returnResult = new Result();

Field resultField = null;
Object result = null;
Class<? extends Object> returnType = ctx.getMethod().getReturnType();

try
{
logger.info("method:{},return type:{}", ctx.getMethod(),
ctx.getMethod().getGenericReturnType());
returnType = ctx.getMethod().getReturnType();
result = ctx.proceed(); // this invoke your service
}
catch ( UsernameInvalidException e )
{
try
{
result = returnType.newInstance();
resultField = result.getClass().getDeclaredField("result");

if ( resultField == null )
{
return null;
}

returnResult.setResultType(ResultType.ERROR);
returnResult.setResultCode(e.getErrorCode()); // code you defined
// error text you set in UsernameInvalidException when thrown
returnResult.setText(e.getMessage());
}
catch ( Exception e1 )
{
e1.printStackTrace();
}
}
catch ( Exception e ) // catch other unexpected exceptions
{
e.printStackTrace();
}

try
{
if ( resultField != null )
{
resultField.setAccessible(true);
resultField.set(result, returnResult);
}
}
catch ( Exception e )
{
e.printStackTrace();
}

return result;
}

}

定义您的异常(exception):

public class BaseException extends RuntimeException {

protected static final String SCANPAY_EXCEPTION_CODE = "300";

protected static final String BASE_EXCEPTION_CODE = "400";

protected static final String USERNAME_INVALID_EXCEPTION_CODE = "405";

protected static final String DAO_EXCEPTION_CODE = "401";

protected static final String SERVICE_NOT_AVAILABLE_CODE = "414";

protected static final String PARAMETER_ERROR_CODE = "402";

protected String errorCode;

public BaseException() {

initErrorCode();
}

public BaseException(String message) {

super(message);
initErrorCode();
}

public BaseException(Throwable cause) {

super(cause);
initErrorCode();
}

public BaseException(String message, Throwable cause) {

super(message, cause);
initErrorCode();
}

public BaseException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {

super(message, cause, enableSuppression, writableStackTrace);
initErrorCode();
}

protected void initErrorCode() {

errorCode = BASE_EXCEPTION_CODE;
}

public String getErrorCode() {

return errorCode;
}

}

您的用户名无效异常:

@SuppressWarnings("serial")
public class UsernameInvalidExcepton extends BaseException {

@Override
@SuppressWarnings("static-access")
protected void initErrorCode() {

this.errorCode = this.USERNAME_INVALID_EXCEPTIO_CODE;
}

public UsernameInvalidException(String message) {

super(message);
}

定义自己的ExceptionHandler,它是一个注释(请参阅此处 custom annotation ):

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.interceptor.InterceptorBinding;

@InterceptorBinding
@Inherited
@Target({ TYPE, METHOD })
@Retention(RUNTIME)
@Documented
public @interface YourExceptionHandler {

}

定义一个异常抛出工厂(这个工厂不是必须的,它只是用来抛出新的不同的异常。当你需要抛出它时,你可以新的异常。):

public abstract class YourExceptionThrowFactory {

private YourExceptionThrowFactory() {

}

public static void throwUsernameInvalidException(String message) {

throw new UsernameInvalidException(message);
}

如何使用它?在您的服务方法中,使用注释:

@YourExceptionHandler
public UserInfo getUserInfo(String username) {
// your service code
if (username == null) {
YourExceptionThrowFactory.throwUsernameInvalidException(
"Username is not valid"); // throw your exception with your message.
}
}

然后对于客户端,它将获取您的错误代码和错误消息。

以上所有代码都是针对JavaEE的,如果你使用spring,你会找到相应的注解和技术。

关于java - JAX-RS 客户端可以抛出自定义异常类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49825860/

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