为什么我的二传手被叫了两次?

时间:2013-12-02 18:30:16

标签: java rest jaxb jax-rs unmarshalling

我正在开发一个REST Web服务,使用JAX-RS,JPA和JAXB来管理游戏及其高分。游戏具有以下属性:nameurlhighscoreTableSize

我正在尝试做的简短描述:我在控制器中使用createRow()方法,该方法使用JSON(Game对象的JSON序列化,类Game正在用@XmlRootElement注释,从createRow()模型类调用静态Game,并在其中调用setUrl()。问题在于,出于某种原因,setter被称为两次

现在发生的是,如果在请求正文中发送的url对模式无效,则在“神秘”第一次调用之后它变为null,第二次调用setter ,它在if (url == null)内,而不是进入if (!matcher.matches()),实际上后者是真实的情况,因为我发送了一个错误的URL。

有谁知道为什么会这样,我该如何解决?

提前谢谢!

课堂游戏:

@Entity
@Table(name="games")
@XmlRootElement(name = "Game")
public class Game implements Serializable {

    //properties

    public void setUrl(String url) throws CustomWebServiceException {
        String regex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
        Pattern pattern = Pattern.compile(regex);

        System.out.println("URL: " + url);
        if ( url == null || url.length() == 0) {
          throw new CustomWebServiceException(Response.Status.BAD_REQUEST, new ErrorMessage("The url of the game is mandatory!"));
        } else {
          Matcher matcher = pattern.matcher(url);
          if (!matcher.matches()) { 
            throw new CustomWebServiceException(Response.Status.BAD_REQUEST, new         ErrorMessage("The url is invalid! Please check its syntax!"));
          } else {
            this.url = url;
          }
        }
    }

    public static Response createRow(EntityManager em, UserTransaction ut, String name, Game gameData) throws Exception {

        ut.begin();

        Game _game = em.find(Game.class, name);

        if (_game != null) {
          Util.tryRollback(ut);
          ErrorMessage errorMessage = new ErrorMessage(
              "The game with name " + name
              + " already exists in the database!");
          throw new CustomWebServiceException(Response.Status.CONFLICT,
              errorMessage);
        }

        String url = gameData.getUrl();
        Integer highscoreTableSize = gameData.getHighscoreTableSize();

        Game newGame = new Game();
        newGame.setName(name);
        newGame.setUrl(url);
        newGame.setHighscoreTableSize(highscoreTableSize);

        em.persist(newGame);

        // force the persistence manager to save data to DB
        ut.commit();

        if (highscoreTableSize == null) {
           highscoreTableSize = 7;
        }

        SuccessfulRequestMessage succesfulRequestMessage = new SuccessfulRequestMessage(
            " Game entry created with name: " + name
            + ", url: " + url + " and highscoreTableSize: " + highscoreTableSize
            + ".");
        return Response.status(Status.CREATED).entity(succesfulRequestMessage).type(MediaType.APPLICATION_JSON).build();
    }
}

控制器:

@PUT
@Path("/{name}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createRow(
  @PathParam("name") String name, 
  Game gameData) throws CustomWebServiceException {

    try {
      return Game.createRow(em, ut, name, gameData);
    } catch (SystemException | NotSupportedException | IllegalStateException | SecurityException | HeuristicMixedException
        | HeuristicRollbackException | RollbackException e) {
      Util.tryRollback(ut);
      ErrorMessage errorMessage = new ErrorMessage(
          "Error when trying to create entry:" + e.toString()
          + " with message: " + e.getMessage());
      throw new CustomWebServiceException(
      Response.Status.INTERNAL_SERVER_ERROR, errorMessage);
    } catch (CustomWebServiceException e) {
       throw e;
    } catch (Exception e) {
      Util.tryRollback(ut);
      ErrorMessage errorMessage = new ErrorMessage(
          "During creation of game data, the following error(s) was(were) encountered: "
              + e.toString());
      throw new CustomWebServiceException(Response.Status.BAD_REQUEST,
          errorMessage);
    }
}

1 个答案:

答案 0 :(得分:0)

好吧,应根据您的代码调用两次。在反序列化期间和自己完成之后:

newGame.setUrl(url);

对于模型和表示使用相同的类通常是一个坏主意。 恕我直言,你应该做什么:

  • 分离您的" JSON"来自您保存在数据库中的对象的游戏
  • 不要在你的安装人员中进行验证。有一个Spring Validation。使用它来确保您的JSON对象有效,然后直接转到数据库。
  • 您可以使用dozer自动将模型对象转换为表示对象,反之亦然

修改 不使用任何库,最简单的方法是将验证移动到控制器中的方法:

void validateInput(Game game) throws Exception {
  if (game == null) {
   throw new Exception("Game object is not present in the request");
  }
  if (game.getUrl() == null || !game.maches({some-fancyreg-exp}) {
   throw new Exception("Game URL is not valid");
  }
  //etc, check the rest of the fields
}

在控制器中调用validateInput(游戏)。之后,您可以确定输入有效。又脏又脏。让setter成为setters。