如何反序列化为Map或数组类,其中Map结构在Java中变化?

wwtsj6pe  于 2023-01-01  发布在  Java
关注(0)|答案(1)|浏览(124)

我需要反序列化外部REST API的响应,通常是JSON对象,但如果发生错误,它将是JSON对象的数组。API缺少文档,因此我通过响应的HTTP Status确定是否发生错误。问题是每个API路由的非错误响应具有不同的结构(用户响应、产品响应等)。另一个问题是,在我的应用程序中,我们使用了一个抽象类进行外部API响应,其字段为errorhasError。我解决了这个问题,如下所示:

public abstract class AbsractApiResponse {
  public abstract String getError();
  public abstract void setError(String error);
  public abstract String getDescription();
  public abstract void setDescription(String error);
}

public class ErrorResponse {
  private String errorCode; // getters/setters

  private String message; // getters/setters
}

public class UserResponse extends AbsractApiResponse {

  private String error; // getters/setters
  private boolean hasError; // getters/setters
  private boolean description; // getters/setters
  private String userName;
  private String userEmail;
}

public <R extends AbsractApiResponse> R deserializeResponse(
    String apiResponse, Class<R> responseType, boolean isHttpError)
    throws JsonProcessingException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
  R response;
  Object deserialized = objectMapper.readValue(apiResponse, Object.class);

  if (isHttpError && deserialized instanceof List) {
    TypeReference<List<ErrorResponse>> errorResponseType = new TypeReference<>() {};
    List<ErrorResponse> responseErrors = objectMapper.convertValue(deserialized,
        errorResponseType);
    Constructor<R> constructor = responseType.getDeclaredConstructor();
    response = constructor.newInstance();
    ErrorResponse firstError = responseErrors.get(0);
    String errorDescription = responseErrors.stream().map(ErrorResponse::toString).collect(Collectors.joining());
    response.setError(firstError.getMessage());
    response.setDescription(errorDescription);
  } else {
    response = objectMapper.convertValue(deserialized, responseType);
  }
  return response;
}

用这种方法我不得不添加像error/hasError这样的字段到每个类中,这些字段代表了一个响应,我想这并不是那么糟糕。另一个危险信号是反射(responseType.getDeclaredConstructor())的使用和伴随它的4个检查异常。我想知道,是否有更好的方法来解决这个问题?

bbmckpt7

bbmckpt71#

我不建议把错误响应和业务对象合并在一起,成功的时候可以返回给定的响应类,出错的时候抛出异常,我认为这是最干净的方式。
如果你不想抛出异常,你可以实现包含responseerror对象的 Package 类。如果设置了error字段,我们就知道有问题。它可能如下所示:

interface ApiResponse {
}

@Data
class ResponseWrapper<R extends ApiResponse> {
    private R response;
    private Error error;

    public boolean hasErrors() {
        return Objects.nonNull(error);
    }
}

@Data
class Error {
    private String error;
    private String description;
}

@Data
class ErrorResponse {
    private String errorCode;
    private String message;
}

@Data
class UserResponse implements ApiResponse {
    private String userName;
    private String userEmail;
}

该方法一般实现可以如下所示:

class JsonDecoder {

    private final ObjectMapper objectMapper = ...;

    public <R extends ApiResponse> ResponseWrapper<R> deserializeResponse(String apiResponse, Class<R> responseType, boolean isHttpError)
            throws JsonProcessingException {
        ResponseWrapper<R> response = new ResponseWrapper<>();

        if (isHttpError) {
            response.setError(deserializeError(apiResponse));
        } else {
            response.setResponse(objectMapper.readValue(apiResponse, responseType));
        }

        return response;
    }

    private Error deserializeError(String apiResponse) throws JsonProcessingException {
        final TypeReference<List<ErrorResponse>> errorResponseType = new TypeReference<>() {};
        List<ErrorResponse> errors = objectMapper.readValue(apiResponse, errorResponseType);

        ErrorResponse firstError = errors.get(0);
        String errorDescription = errors.stream().map(ErrorResponse::toString).collect(Collectors.joining());

        Error error = new Error();
        error.setError(firstError.getMessage());
        error.setDescription(errorDescription);
        return error;
    }
}

相关问题