I'm found the reason of double resolving. I didn't mentioned before, that I'm using Thymeleaf as template engine (which is using SpringEL). There are an useful snippet in example app, which I just copy-paste (shame on me) and forgot about:
<div class="errors" th:if="${#fields.hasErrors('*')}" th:fragment="validationErrorTpl">
<ul>
<li th:each="err : ${#fields.errors('*')}" th:text="#{${err}}">Input is incorrect</li>
</ul>
</div>
As you can see ${err}
variable enclosed in #{}
, which is actually resolving message from bundle. So with braces in validation constraint, message was resolved twice: on annotation level and in view template.