Creating internationalized standard javax.validation error messages - spring

I have a small requirement of writing standardized, internationalized javax.validation error messages in this format
#NotNull
private String name;
#Max(10)
private int age;
Then in this case the error message should prop up as
"The field name is not null"
"The field age is not greater than or equal to 10"
How can I achieve this in a more dynamic way instead of hard-coding the message or variable name inside the annotation.

#NotNull(message = "{errors.name.missing.msg}")
private String name;
define the value for errors.name.missing.msg in messages.properties (which should be available in your classpath)
You can also make it locale specific by placing it in locale specific property files say in messages_en.properties and messages_fr.properties for i18n.

Related

validate ConfigurationProperties mapping

Is there a way to validate application.properties (or yml) if the properties match Java bean that it is mapped to via #ConfigurationProperties - so that if there is a typo in an attribute, exception will be thrown?
I tried using #Validated but it works only if every property has #NotNull annotation - but this is not exactly what I want to achieve... there may be some nullable properties in the config and I still want to "validate" them
I just spent 2 hours debugging an issue and I found out, the problem is that I misspelled an attribute name
e.g. application.yml
property1: 1
properrrrrty2: 2
#Configuration
#ConfigurationProperties
public class AppConfig {
private String property1;
private String property2; // <--- this property does not match due to typo in application.yml
}
A)
If you want to be sure that always a property exists then use #Validated with #NotNull for that property. #NotNull will complain if it does not find that property. You can still have the property there with an empty value if that is what you mean with nullable properties and NotNull will not complain.
You can't say I want it to be able to be nullable but also the validator should complain when that property is null.
So to sum things up.
#NotEmpty property must exist and also not have an empty value
#NotNull property must just exist. It does not care if it exists with an empty value.
That's why I insist you go with NotNull for your requirements.
B)
Also I can think of another way to handle that.
#Component
public class AppConfig {
#Value("${property1}")
private String property1;
#Value("${property2}")
private String property2;
}
Using injection with #Value, spring will fail to initialize the singleton AppConfig during application startup if some property with exactly the same name does not exist on properties file, therefore you will be informed that no property with that name exists and the application will not start up.
You can specify ignoreUnknownFields = false to ensure that no unknown properties are defined under the corresponding prefix. (docs):
Flag to indicate that when binding to this object unknown fields should be ignored. An unknown field could be a sign of a mistake in the Properties.
Borrowing from your example:
#Configuration
#ConfigurationProperties(prefix = "myapp", ignoreUnknownFields = false)
public class AppConfig {
private String property1;
private String property2;
}
This means myapp.property1 and myapp.property2 are allowed but not required to be set, so they remain nullable.
Any other set property with the myapp prefix (such as myapp.properrrrrty2=2) will cause a startup failure and the offending property name will be logged in the exception.

Spring boot using placeholders in messages.properties

I'm working with Spring Boot 2.1.5, and I'm using javax annotations to validate my class properties. So for example, I have:
class MyClass {
#NotEmpty(message = "{validation.notEmpty}")
private String company;
}
Then I have a messages.properties file that contains:
validation.notEmpty={0} is missing
I was hoping to get the error message "company is missing", but instead I'm getting "{0} is missing". What is the proper way of passing my variable name as placeholder?
Thanks.
You cannot achieve such a thing because #NotEmpty resolves the placeholder and get that value as message, it doesn't pass it to the placeholder to be added as parameter.
Look at the default message :
javax.validation.constraints.NotEmpty.message = must not be empty
You can just pass a string as value.
Validation messages are not default not designed to hold the field name. That is retrievable from the ConstraintViolation objects that provide (among other things) paths for each validation error.
So to achieve your requirement, what you could do is creating a custom annotation/validator with a second attribute :
#NotEmpty(message = "{validation.notEmpty}", field="company")
private String company;
But doing it for every kind of constraints you use looks an overhead.
Maybe just accept the duplication that is simple to refactor :
#NotEmpty(message = "car is missing")
private String company;
Note that you loses the benefit from locales, which may be undesirable if you handle multiple languages.
In this case, a more robust approach would be to use ConstraintViolations that has the path value of the field.
If my view doesn't address your issue, I encourage to post the question in the Hibernate Validator issues tracker.

findById() gives No property Id found

I have three entities.
(I am using xxx as a place holder for this example)
I have set up all their #Entities with
#Entity
#Table(name = "xxx")
public class xxx {
#Id
#Column(name = "xxx_id")
int xxx_id;
However, I am able to do:
findById(int ...) for only ONE of the entities in their respective Repository.
When I try to do that for the other two entities, I get this problem:
"Invalid derived query! No property id found for type xxx!"
I am able to run it and get the proper results. But why am I getting this error for two entities but not the other?
I set up the entities and their repositories exactly the same way.
The ONLY difference is that in the entity whose repository does not return any errors, I am joining that entity with another entity whose repository fails, but I used "mappedBy" in the #JoinColumns section.
Could that have something to do with why that one has no problems?
How findBy... works?
Entity:
private int clientid;
private String firstname;
private String lastname;
Query:
findBy<Name_as_per_entity>
findByClientid(int clientid);
findByFirstnameAndLastname(String firstname, String lastname)
Solution
Because we treat the underscore character as a reserved character, we
strongly advise following standard Java naming conventions (that is,
not using underscores in property names but using camel case instead).
Doc
The underscore _ is a reserved character in Spring Data query derivation to potentially allow manual property path description.
Stick to the Java naming conventions of using camel-case for member variable names and everything will work as expected.
Also Refer this

Spring Data JPA - How to find by param with underscore

Here is my model:
public class Log {
#Id
private String id;
private String project;
private String test_no;
// Constructor, getters and setters.
}
How can I add a findBy query which allows me to finding an element by its test_no value? I have tried those method headers but they don't work:
List<Log> findByTest_No(String test_no);
The error that my STS reports is: Invalid delivery query! No property test found in type Log!
List<Log> findByTest_no(String test_no);
The error that my STS reports is: Invalid delivery query! No property test found in type Log!
List<Log> findByTestno(String test_no);
The error that my STS reports is: Invalid derived query! No property testno found for type Log! Did you mean 'test_no'?
It seems that _ is a special character which separates properties names
... it is possible for the algorithm to select the wrong property ... To resolve this ambiguity you can use \_ inside your method name to manually define traversal points ...
Docs
So it can't find test field in Log class.
Try to use:
#Query("select log from Log log where log.test_no = ?1")
List<Log> findByTestNo(String testNo);
There is no need to use private String test_no; You may use private String testNo; Spring automatically understand that you are binding test_no column in the database. Also you can use
#Column(name = "test_no")
private String testNo;
After this changes you can execute queries, mentioned in your question without any custom sql.
List<Log> findByTestNo(String testNo);

bean validation get parameter jsf

Using bean validation like:
#Size(max = 5)
private String name;
How do I retrieve the max value to use within my JSF site? For example to set maxlength value in input text component.

Resources