英文:
How to replace if-else blocks in Java when working with derived types from the basic Throwable?
问题
以下是您提供的代码的翻译部分:
例如,有一个代码,根据类型**Throwable**的子类型,将填充对象并将其返回给调用点。
@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Map<String, Object> map = new LinkedHashMap<>();
Throwable error = super.getError(request);
HttpStatus errorStatus;
String messageDetail = null;
if (error instanceof UserAlreadyExistsException) {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.NOT_ACCEPTABLE;
log.error("error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
}
if (error instanceof UserNotFoundException ||
error instanceof ResponseStatusException || error instanceof PasswordInHashNotFoundException) {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.NOT_FOUND;
log.error("error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
} else if (error instanceof BadSqlGrammarException) {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.NOT_ACCEPTABLE;
log.error("BadSqlGrammar error: error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
} else {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.INTERNAL_SERVER_ERROR;
log.error("Not defined error: error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
}
map.put("status", errorStatus.value());
map.put("message", error.getMessage());
map.put("detailMessage", messageDetail);
return map;
}
}
我创建了一个模型如下
Map<Throwable, Supplier<String>> handler = new LinkedHashMap<>();
PasswordInHashException passwordInHashException =
new PasswordInHashException("passwordInHashException", new Throwable());
PasswordInHashNotFoundException passwordInHashNotFoundException =
new PasswordInHashNotFoundException("passwordInHashException");
handler.put(passwordInHashException, () -> {
System.out.println("passwordInHashException");
return "passwordInHashException";
});
handler.put(passwordInHashNotFoundException, () -> {
System.out.println("passwordInHashNotFoundException");
return "passwordInHashNotFoundException";
});
然而,困难在于如何使用instanceof运算符强制在Map中检查键。
由于有许多异常类型,并且这种方法将增长,但我希望能够在不更改此方法的情况下扩展处理新异常的能力。更好的是使用Spring的自动组件初始化功能,然后只需实现一个新类型,它将自动添加到Map中,并且如果需要,根据发生的异常返回填充对象并执行程序化操作(例如,写入日志)。
Map<String, Supplier<String>> handler = new HashMap<>();
PasswordInHashException passwordInHashException =
new PasswordInHashException("passwordInHashException", new Throwable());
handler.put("PasswordInHashException", () -> {
System.out.println("passwordInHashException");
return "passwordInHashException";
});
Throwable key = new PasswordInHashException("passwordInHashException", new Throwable());
String simpleName = key.getClass().getSimpleName();
handler.get(simpleName).get();
请分享您的想法。
英文:
For example, there is a code that, depending on the subtype of the type Throwable, will fill the object with data and return it to the call point.
@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Map<String, Object> map = new LinkedHashMap<>();
Throwable error = super.getError(request);
HttpStatus errorStatus;
String messageDetail = null;
if (error instanceof UserAlreadyExistsException) {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.NOT_ACCEPTABLE;
log.error("error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
}
if (error instanceof UserNotFoundException ||
error instanceof ResponseStatusException || error instanceof PasswordInHashNotFoundException) {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.NOT_FOUND;
log.error("error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
}else if (error instanceof BadSqlGrammarException) {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.NOT_ACCEPTABLE;
log.error("BadSqlGrammar error: error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
} else {
Throwable cause = error.getCause();
if (cause != null) {
messageDetail = error.getCause().getMessage();
}
errorStatus = HttpStatus.INTERNAL_SERVER_ERROR;
log.error("Not defined error: error - {}, status - {}, detailMessage - {}",
error.getMessage(),
errorStatus,
messageDetail);
}
map.put("status", errorStatus.value());
map.put("message", error.getMessage());
map.put("detailMessage", messageDetail);
return map;
}
}
A made a model like this
Map<Throwable, Supplier<String>> handler = new LinkedHashMap<>();
PasswordInHashException passwordInHashException =
new PasswordInHashException("passwordInHashException", new Throwable());
PasswordInHashNotFoundException passwordInHashNotFoundException =
new PasswordInHashNotFoundException("passwordInHashException");
handler.put(passwordInHashException, () -> {
System.out.println("passwordInHashException");
return "passwordInHashException";
});
handler.put(passwordInHashNotFoundException, () -> {
System.out.println("passwordInHashNotFoundException");
return "passwordInHashNotFoundException";
});
However, the difficulty lies in how to force the key to be checked in Map using the instanceof operator.
Since there are a lot of Exceptions types and this method will grow, but I would like to make it so that without changing this method, expand the ability to process new Exceptions. And it is even better to use Spring's capabilities for automatic initialization of components, then it is enough to implement a new type that will be automatically added to the Map and, if necessary, depending on the exceptions that occurred, the filled object was returned and a programmed action was performed (for example, writing to the log).
Map<String, Supplier<String>> handler = new HashMap<>();
PasswordInHashException passwordInHashException =
new PasswordInHashException("passwordInHashException", new Throwable());
handler.put("PasswordInHashException", () -> {
System.out.println("passwordInHashException");
return "passwordInHashException";
});
Throwable key = new PasswordInHashException("passwordInHashException", new Throwable());
String simpleName = key.getClass().getSimpleName();
handler.get(simpleName).get();
Please share your ideas.
答案1
得分: 0
以下是您的代码的中文翻译:
有几种选择:
# 1. 多态
异常自己知道在这里如何行为
记录 StatusAndMessage(HttpStatus errorStatus, String message, String messageDetail) {}
接口 SelfHandling {
StatusAndMessage handle()
}
@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Throwable error = super.getError(request);
StatusAndMessage statusAndMessage;
if (error instanceof SelfHandling selfHandling) {
statusAndMessage = selfHandling.statusAndMessage()
} else {
statusAndMessage = new StatusAndMessage(
HttpStatus.INTERNAL_SERVER_ERROR,
error.getMessage(),
error.getCause() != null ? error.getCause().getMessage() : null;
)
}
log.error("未定义的错误:错误 - {},状态 - {},详细消息 - {}",
statusAndMessage.message(),
statusAndMessage.errorStatus(),
statusAndMessage. messageDetail());
map.put("status", statusAndMessage.errorStatus().value());
map.put("message", statusAndMessage.message());
map.put("detailMessage", statusAndMessage. messageDetail());
return map;
}
}
- 不利之处:对于第三方异常无效。因此,您必须包装自己的异常,或选择不同的方法。
- 优势:如果定义新异常,则无需更改此方法。
# 2. 双重分发
- 不利之处:丑陋(因此没有代码示例)
- 优势:可以根据上下文变化行为。例如,根据请求,异常可能需要不同的状态。
# 3. 责任链
// 如果无法处理Throwable,则实现将返回Optional.empty()
interface ExceptionToResponseMapper extends Function<Throwable, Optional<StatusAndMessage>> {
}
@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
private final List<ExceptionToResponseMapper> mappers;
// mappers的顺序很重要
public GlobalErrorAttributes(List<ExceptionToResponseMapper> mappers) {
this.mappers = List.copyOf(mappers);
}
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Throwable error = super.getError(request);
StatusAndMessage statusAndMessage = mappers.stream()
.map(mapper -> mapper.apply(error))
.flatMap(Optional::stream)
.findFirst()
.orElseGet(() -> new StatusAndMessage(
HttpStatus.INTERNAL_SERVER_ERROR,
error.getMessage(),
error.getCause() != null ? error.getCause().getMessage() : null
));
log.error("未定义的错误:错误 - {},状态 - {},详细消息 - {}",
statusAndMessage.message(),
statusAndMessage.errorStatus(),
statusAndMessage. messageDetail());
map.put("status", statusAndMessage.errorStatus().value());
map.put("message", statusAndMessage.message());
map.put("detailMessage", statusAndMessage. messageDetail());
return map;
}
}
- 不利之处:在引入新异常时容易忘记编写额外的处理程序。
- 优势:在第三方异常上轻松工作。
希望这有助于您理解代码的中文翻译。如果您有任何其他问题,请随时提出。
英文:
There are a few options :
1. Polymorphism
The exceptions know how to behave here themselves
record StatusAndMessage(HttpStatus errorStatus, String message, String messageDetail) {}
interface SelfHandling {
StatusAndMessage handle()
}
@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Throwable error = super.getError(request);
StatusAndMessage statusAndMessage;
if (error instanceof SelfHandling selfHandling) {
statusAndMessage = selfHandling.statusAndMessage()
} else {
statusAndMessage = new StatusAndMessage(
HttpStatus.INTERNAL_SERVER_ERROR,
error.getMessage(),
error.getCause() != null ? error.getCause().getMessage() : null;
)
}
log.error("Not defined error: error - {}, status - {}, detailMessage - {}",
statusAndMessage.message(),
statusAndMessage.errorStatus(),
statusAndMessage. messageDetail());
map.put("status", statusAndMessage.errorStatus().value());
map.put("message", statusAndMessage.message());
map.put("detailMessage", statusAndMessage. messageDetail());
return map;
}
}
- Downside : This doesn't work for 3rd party exceptions. So you have to either wrap those in your own, or choose a different approach.
- Upside : this method doesn't need to change if you define new Exceptions
2. Double dispatch
- Downside : ugly (so no code example)
- Upside : You can vary behavior
per context. If exceptions may need a different status depending on
the request for instance.
3. Chain of Responsibility
// implementations will return Optional.empty() if they can't handle the Throwable
interface ExceptionToResponseMapper extends Function<Throwable, Optional<StatusAndMessage>> {
}
@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
private final List<ExceptionToResponseMapper> mappers;
// order of the mappers matters
public GlobalErrorAttributes(List<ExceptionToResponseMapper> mappers) {
this.mappers = List.copyOf(mappers);
}
@Override
public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
Throwable error = super.getError(request);
StatusAndMessage statusAndMessage = mappers.stream()
.map(mapper -> mapper.apply(error))
.flatMap(Optional::stream)
.findFirst()
.orElseGet(() -> new StatusAndMessage(
HttpStatus.INTERNAL_SERVER_ERROR,
error.getMessage(),
error.getCause() != null ? error.getCause().getMessage() : null
));
log.error("Not defined error: error - {}, status - {}, detailMessage - {}",
statusAndMessage.message(),
statusAndMessage.errorStatus(),
statusAndMessage. messageDetail());
map.put("status", statusAndMessage.errorStatus().value());
map.put("message", statusAndMessage.message());
map.put("detailMessage", statusAndMessage. messageDetail());
return map;
}
}
- Downside : easy to forget writing extra handlers when introducing a new Exception
- Upside : works easily on 3rd party exceptions
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论