【问题标题】:Java how to store object of varying typeJava如何存储不同类型的对象
【发布时间】:2017-01-12 07:55:57
【问题描述】:

我目前正在使用 Spring MVC 和 Hibernate 来开发我的 Web 应用程序。仍在学习java的内部工作原理。

我发现自己需要将数据存储在一个可以接受不同类型的对象以及其他一些数据字符串的字段中。更准确地说,我想创建一个可以保存消息、错误代码等的 ReturnObject。这样我的返回 JSON 可以在整个 api 中保持一致。

这就是我创建 ReturnObject 的方式

public class ReturnResponse {

//Set fields
private Object returnObj;      <----- Need this to accept different types
private HttpStatus httpStatus;
private String message;
private String developerMessage;

// Start build

public ReturnResponse(){
    this.returnObj =        returnObj;
    this.httpStatus =.....etc.
}

// Setters... getters...
}

private Object returnObj; 以便该字段可以接受 Collection、Maps、Class..等,但这安全吗?

我似乎记得,在字段中声明特定对象类型以确保类型安全始终是一个好习惯。

问题

  1. 您是否看到未来可预见的问题,是否有更好的方法来做到这一点?

  2. 如果这不是类型安全的,我该如何让它更安全。

【问题讨论】:

  • Object returnObj更改为Serializable returnObj
  • 我认为你应该只返回预期的消息。如果出现错误,您应该使用错误处理程序来执行此操作。这样您也可以避免这种困境,并且代码更具可读性。
  • Object 的问题在于它可以接受任何对象,并且您必须执行强制转换才能访问其中的成员。而且由于它可能接受任何对象,因此您可能很难确定应该将其向下转换为哪个类。 (只是我过去的经验)
  • 类型范围有多广?这是一种“域”吗?也许从 IMyBasicPiecieOfData 继承可以帮助你
  • 如果您返回 json,也许您应该考虑使用诸如 jersey 之类的库,再加上例如 jackson,来处理适当的休息端点。 json 是 json,它只是一个字符串。对象映射不是在休息点一侧(至少不一定)而是在调用者一侧完成。

标签: java


【解决方案1】:

您可以使用泛型:

public class ReturnResponse<ObjectType> {

    private ObjectType returnObj;
    private HttpStatus httpStatus;
    private String message;
    private String developerMessage;

    public ReturnResponse(ObjectType returnObj, /*other parameters...*/) {
        this.returnObj = returnObj;
        // set other parameters
    }

    public ObjectType getReturnObj() {
        return this.returnObj;
    }

    // ...
}

如果您知道实例化 ReturnResponse 时返回的对象的类型是什么,它将起作用。 我在我的大部分 API 中使用这种模式没有问题。

【讨论】:

  • 因为我的 ReturnResponse 将有其他字段,如字符串消息等。我可以将&lt;&gt; 移动到现场吗? private Object&lt;T&gt; returnObj?这行得通吗?
  • @EricHuang 我省略了您示例的其他字段,但您可以毫无问题地添加它们。我编辑了我的答案。
【解决方案2】:

如果您希望 “将数据存储在可以接受不同类型的对象以及其他一些数据字符串的字段中。” 那么您需要为该对象创建一个基类,该基类在您的case 可能是 Object

问题是您需要稍后在代码中破译它是什么类型的对象 - 在大多数情况下,我认为这是不受欢迎的并且需要不安全的转换。

我能想到的让它更安全的唯一方法是制作某种包装器,例如:

public class Bean {
   private String string;
   private Integer integer;
   private List<String> list;
   private Bicycle bicycle;


   //setters
   //...

   public Optional<Bicycle> getBicycle() {
      return Optional.ofNullable(bicycle);
   }

   //... and so on...
}

【讨论】:

    【解决方案3】:

    错误处理程序应该在控制器中,它应该响应一个 http 错误。这意味着正确的 HTTP 错误状态和所需的错误消息。错误不应看起来像是成功的请求(无状态代码 200)。这是一个错误。在您的前端,您应该相应地处理 http 错误响应。

    使用 spring 这可以很容易地完成。这是我的一个项目的错误处理程序的示例。它是一个带有注释@ControllerAdvice 的自己的类。 spring 会自动使用它。

    该类将自动捕获使用@ExceptionHandler 定义的任何未处理的异常,并在我的情况下发送一个ShortExceptionResponse,其中包含抛出的异常的类型和消息,以及使用@ResponseStatus 定义的正确Http 错误状态.

    在您的前端,您可以对不同的 HTTP 状态错误代码做出相应的反应。它既好又通用。

    @ControllerAdvice
    public class RestExceptionResponseHandler {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SetRestController.class);
    
        @ExceptionHandler(NoSuchElementException.class)
        @ResponseStatus(HttpStatus.NOT_FOUND)
        public @ResponseBody
        ShortExceptionResponse noSuchElementExceptionHandler(Exception ex) {
        LOGGER.error("An error occured processing a rest request", ex);
        return new ShortExceptionResponse(ex);
        }
    
        @ExceptionHandler(value = {EntityAlreadyExistsException.class})
        @ResponseStatus(HttpStatus.FORBIDDEN)
        public @ResponseBody
        ShortExceptionResponse entityAlreadyExistsExceptionHandler(EntityAlreadyExistsException ex) {
        LOGGER.debug("A rest request could not been process due an illegal state of the target entity", ex);
        return new ShortExceptionResponse(ex);
        }
    
        @ExceptionHandler(value = {IllegalArgumentException.class, UnsupportedOperationException.class})
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public @ResponseBody
        ShortExceptionResponse illegalArgumentExceptionHandler(Exception ex) {
        LOGGER.error("An error occured processing a rest request", ex);
        return new ShortExceptionResponse(ex);
        }
    
        @ExceptionHandler(value = {HttpMessageNotReadableException.class})
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public @ResponseBody
        ShortExceptionResponse httpMessageNotReadableExceptionHandler(Exception ex) {
        LOGGER.error("An error occured processing a rest request", ex);
        if (ex.getCause() instanceof InvalidFormatException) {
            return new ShortExceptionResponse(new InvalidValueException(((InvalidFormatException) ex.getCause()).getOriginalMessage()));
        }
        return new ShortExceptionResponse(ex);
        }
    ...
    ...
    }
    

    在实际的控制器中,您只需不断抛出异常,它将由您的错误处理程序处理

    @RequestMapping(method = RequestMethod.POST)
    public @ResponseBody
    MetadataDTO createMetadata(@RequestBody MetadataDTO metaDataDTO) throws EntityAlreadyExistsException {
        MetadataDTO result = metaDataService.createMetadata(metaDataDTO.getName(), metaDataDTO.getDescription(), metaDataDTO.getType());
        return result;
    }
    

    【讨论】:

    • 感谢您分享此内容。这是处理异常的非常干净的方法。我正在使用 try 和 catch 块,这就是为什么我想创建一个 ReturnObject 以便我可以为其设置错误消息...我注意到您明确设置了 HttpStatus,如果抛出异常,它不会自动发送不是 200 状态代码吗?
    • 服务器端异常的默认一般http错误码为500。但是如果客户端发送的请求带有错误的参数等,则不是服务器的错误。所以500是错误的。当然,它仍然有效。同样使用不同的错误代码,我可以在前端对它们做出不同的反应。
    • 我认为您的代码比我以前的代码好 100% ......非常感谢您的回答。我对你的帖子投了赞成票....
    • 很高兴帮助 :) 谢谢
    【解决方案4】:

    您可以创建一个“模型”类来存储要转换为 json 的完整对象:

    @AllArgsConstructor //or make a constructor with all the fields manually
    class ResponseObject {
        User user;
        House house;
        Car car;
    }
    

    由于您使用的是 Spring,因此您已经拥有了 Jackson 库。所以你可以这样做:

    @Autowired ObjectMapper objectMapper; // no need to configure anything to use this
    public String getJson(){
        User user = new User("user", "password");
        House house = new House(4, true, ...);
        Car car = new Car();
        ResponseObject resp = new ResponseObject(user, house, car);
        String json = null;
        json = objectMapper.convertValue(resp, ResponseObject.class);
        // or:
        try {
            json = objectMapper.writeValueAsString(resp);
        } catch (Exception e) {
            ...
        }
        // or: (would need to use a google Gson dependency)
        Gson gson = new Gson();
        json = gson.toJson(resp, ResponseObject.class);
        return json;
    }
    

    或者,如果你真的需要灵活性,

    @Autowired ObjectMapper mapper;
    public void printJson() {
        Map<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("number", 5);
        jsonMap.put("String", "string");
        jsonMap.put("kanky", 987L);
        String json = mapper.writeValueAsString(jsonMap);
        System.out.println("json: " + json);
    } // works fine if your map values have a toString defined
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-30
      • 1970-01-01
      • 1970-01-01
      • 2018-06-21
      相关资源
      最近更新 更多