Tuesday, February 16, 2016

Spring framework has issues with periods

I didn't know what it was initially, but I found stuff like this, this and this.

The one other thing that stood out to me was when I moused over @RequestMapping in Eclipse and one of the list of arguments was noted as such:
  • @PathVariable annotated parameters (Servlet-only) for access to URI template values (i.e. /hotels/{hotel}). Variable values will be converted to the declared method argument type. By default, the URI template will match against the regular expression [^\.]* (i.e. any character other than period), but this can be changed by specifying another regular expression, like so: /hotels/{hotel:\d+}.
 Simply put, if you URL ends with a period "." then Spring defaults to assuming it could be a file extension, and will strip off anything after the dot and return whatever string preceding it.

My annotation went from

@RequestMapping(value = "/fruits/{fruitName}", method = RequestMethod.GET)

Into inclusion of a simple regex that factors in the period symbol

@RequestMapping(value = "/fruits/{fruitName:.+}", method = RequestMethod.GET)

Monday, February 1, 2016

Submitting HashMap from JSP with JSTL in Spring framework 4.2.1

The Controller I'm currently working on has this model that it uses, let's just say it is
public class RecipeModel implements Serializable {
  private String recipeName; //not important
  private String authorName; //not important
  private Map<String, Ingredient> ingredients;
  //get and set methods
}

And the Ingredient class of course,
public class Ingredient implements Serializable {
  private String ingredientName;
  private String preparationStyle;
  private String useAtStage;
  //get and set methods
}

Obviously, the above are placeholder examples I'm using, in place of the actual objects I have, so while the scenario may not be ideal, it is just meant to describe the situation.

The JSP managed to display (via JSTL) the model values without a hitch:
<c:forEach items="${recipeModel.ingredients}" var="ingredientMap">
  <input name="ingredientMap['${ingredientMap.key}']" value="${ingredientMap.value.ingredientName}" />
</c:forEach>

The problem arose when I needed to return the amended changes back to the server. The solutions I found seemed either too outdated or tedious. It also didn't help that I had mispelt ingredientmap with a lowercase 'M' either.

What worked?

<input name="ingredientMap['${ingredientMap.key}']" value="${ingredientMap.value.ingredientName}" />
<input name="ingredientMap['${ingredientMap.key}'].useAtStage" value="${ingredientMap.value.useAtStage}" />
<input name="ingredientMap['${ingredientMap.key}'].preparationStyle" value="${ingredientMap.value.preparationStyle}" />

Append the property name (don't forget the dot) after the bracket for the map. Spring is able to translate each field accordingly into the corresponding property of the value object in the map.

That was it. No CustomMapEditor to add in the InitBinder, no mapping of spring:binder stuff anywhere else. Mistakes were made. Mischief managed.