Michael Osipov opened SPR-13590 and commented

Consider this code snippet:

@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<RestError> handleMethodArgumentTypeMismatchException(
    MethodArgumentTypeMismatchException e) {
  String message = messages.getMessage(
      "error.projects.invalid_parameter." + e.getName() + ".type_mismatch",
      new Object[] { e.getValue(), e.getName() },
      messages.getMessage("error.projects.invalid_parameter.type_mismatch", new Object[] {
          e.getValue(), e.getName() }));

  RestError error = new RestError(Reason.INVALID_PARAMETER, message;

  return new ResponseEntity<RestError>(error, HttpStatus.BAD_REQUEST);
}

using the following signature:

public String getMessage(String code, Object[] args, String defaultMessage)

Where bundle looks like

error.projects.invalid_parameter.type_mismatch = Der \u00FCbergebene Wert ''{0}'' für Parameter ''{1}'' ist fehlerhaft/ung\u00FCltig

The default message shall provide a generic information if a parameter-specific message code is not available.

The expected behavior is:

Der übergebene Wert 'dd' für Parameter 'omitEmptyResponse' ist fehlerhaft/ungültig

but the output is:

Der übergebene Wert dd für Parameter omitEmptyResponse ist fehlerhaft/ungültig

The quotes are lost because the default message is passed through MessageFormat. This behavior is not documented. The signature says: code and defaultMessage and not code and defaultCode.

This is either bad documentation or bad implementation. I opt for the latter.

The outcome is that one needs to double-escape the quotes. Making them unusable for code but only for defaultMessage.


Affects: 4.2.2

Comment From: jhoeller

The above is actually a bit of a misunderstanding since the defaultMessage argument is not supposed to be a pre-resolved message but rather a message template which still gets the provided arguments substituted. From that perspective, this works as designed.