Java 为什么我的二传手要打两次电话?
我正在开发一个RESTWeb服务,使用JAX-RS、JPA和JAXB来管理游戏及其高分。游戏具有以下属性:Java 为什么我的二传手要打两次电话?,java,rest,jaxb,jax-rs,unmarshalling,Java,Rest,Jaxb,Jax Rs,Unmarshalling,我正在开发一个RESTWeb服务,使用JAX-RS、JPA和JAXB来管理游戏及其高分。游戏具有以下属性:name、url和highscoreTableSize 我尝试做的一个简短描述:我在控制器中有createRow()方法,该方法使用JSON(一个Game对象的JSON序列化,类Game被注释为@XmlRootElement),它从Game模型类调用静态createRow(),在它内部调用setUrl()。问题是,出于某种原因,二传手被称为两次 现在发生的情况是,如果请求主体中发送的url对
name
、url
和highscoreTableSize
我尝试做的一个简短描述:我在控制器中有createRow()
方法,该方法使用JSON(一个Game
对象的JSON序列化,类Game
被注释为@XmlRootElement
),它从Game
模型类调用静态createRow()
,在它内部调用setUrl()
。问题是,出于某种原因,二传手被称为两次
现在发生的情况是,如果请求主体中发送的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);
}
}
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
}
嗯,它应该按照您的代码调用两次。在反序列化期间和您自己进行反序列化时:
newGame.setUrl(url);
一般来说,将同一类用于模型和表示是一个坏主意。
IMHO,你应该做什么:
- 将“JSON”游戏与保存在数据库中的对象分开
- 不要在setter中进行验证。这是有道理的。使用它来确保JSON对象有效,然后直接进入数据库
- 可以使用推土机将模型对象自动转换为表示对象,反之亦然
@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);
}
}
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(游戏)。之后,您可以确保输入是有效的。又快又脏。让设定者成为设定者。你有什么建议?使用弹簧或推土机并不是一个真正的选择。这个web服务有教育目的,Spring和Dozer还没有被研究过。JAXB什么时候第一次调用我的setter?它在创建
游戏gamaData
参数时会这样做吗?@SorinAdrianCarbunaru-yup。解析响应并将结果填充到新的游戏对象中。这是二传手被叫来的时候,嗯?什么反应?我猜您引用了请求主体中的JSON字符串,不是吗?