ErrorDetails.java
package com.shengzhiai.yugu.errors;
/**
* Immutable description of an error, used to construct {@link YuguException} and its subclasses.
*
* <p>Most callers never build one: the SDK creates exceptions through {@link YuguErrors}. The class
* is public so that tests and wrappers can create SDK exceptions with full context.
*/
public final class ErrorDetails {
final ErrorCategory category;
final int code;
final CodeKind codeKind;
final int httpStatus;
final String message;
final String idempotencyKey;
final String recordId;
final int attempts;
final String rawBody;
final long retryAfterMs;
final Throwable cause;
private ErrorDetails(Builder b) {
this.category = b.category == null ? ErrorCategory.UNKNOWN : b.category;
this.code = b.code;
this.codeKind = b.codeKind == null ? YuguErrors.kindOf(b.code) : b.codeKind;
this.httpStatus = b.httpStatus;
this.message = b.message == null ? "" : b.message;
this.idempotencyKey = b.idempotencyKey;
this.recordId = b.recordId;
this.attempts = b.attempts;
this.rawBody = truncate(b.rawBody);
this.retryAfterMs = b.retryAfterMs;
this.cause = b.cause;
}
/** Maximum length of {@link YuguException#getRawBody()}, 4 KB as required by the design. */
public static final int RAW_BODY_LIMIT = 4096;
static String truncate(String s) {
if (s == null) {
return null;
}
if (s.length() <= RAW_BODY_LIMIT) {
return s;
}
return s.substring(0, RAW_BODY_LIMIT);
}
/** @return a new builder */
public static Builder builder() {
return new Builder();
}
/** @return a builder initialised with the values of this instance */
public Builder toBuilder() {
Builder b = new Builder();
b.category = category;
b.code = code;
b.codeKind = codeKind;
b.httpStatus = httpStatus;
b.message = message;
b.idempotencyKey = idempotencyKey;
b.recordId = recordId;
b.attempts = attempts;
b.rawBody = rawBody;
b.retryAfterMs = retryAfterMs;
b.cause = cause;
return b;
}
/** @return error category */
public ErrorCategory getCategory() {
return category;
}
/** @return business or local code, 0 when none */
public int getCode() {
return code;
}
/** @return table the code belongs to */
public CodeKind getCodeKind() {
return codeKind;
}
/** @return HTTP status, 0 when none */
public int getHttpStatus() {
return httpStatus;
}
/** @return message */
public String getMessage() {
return message;
}
/** Builder for {@link ErrorDetails}. */
public static final class Builder {
private ErrorCategory category;
private int code;
private CodeKind codeKind;
private int httpStatus;
private String message;
private String idempotencyKey;
private String recordId;
private int attempts = 1;
private String rawBody;
private long retryAfterMs = -1;
private Throwable cause;
private Builder() {
}
/** @param v category @return this builder */
public Builder category(ErrorCategory v) {
this.category = v;
return this;
}
/** @param v business or local code, 0 for none @return this builder */
public Builder code(int v) {
this.code = v;
return this;
}
/** @param v table of the code; derived from the code when not set @return this builder */
public Builder codeKind(CodeKind v) {
this.codeKind = v;
return this;
}
/** @param v HTTP status, 0 for none @return this builder */
public Builder httpStatus(int v) {
this.httpStatus = v;
return this;
}
/** @param v message @return this builder */
public Builder message(String v) {
this.message = v;
return this;
}
/** @param v idempotency key of the call @return this builder */
public Builder idempotencyKey(String v) {
this.idempotencyKey = v;
return this;
}
/** @param v platform record id when known @return this builder */
public Builder recordId(String v) {
this.recordId = v;
return this;
}
/** @param v number of attempts made @return this builder */
public Builder attempts(int v) {
this.attempts = v;
return this;
}
/** @param v raw response body or frame, truncated to 4 KB @return this builder */
public Builder rawBody(String v) {
this.rawBody = v;
return this;
}
/** @param v server Retry-After in milliseconds, -1 for none @return this builder */
public Builder retryAfterMs(long v) {
this.retryAfterMs = v;
return this;
}
/** @param v cause @return this builder */
public Builder cause(Throwable v) {
this.cause = v;
return this;
}
/** @return the immutable details */
public ErrorDetails build() {
return new ErrorDetails(this);
}
}
}