Spring Boot - custom validation message with annotation parameters - java

I want to create my custom validation messages with Spring Boot/MVC Validation.
I found following setup working:
public class RegisterCredentials {
#NotEmpty
#NotNull
#Size(min=3, max=15)
private String username;
...
}
messages.properties:
NotEmpty.registerCredentials.username = Username field cannot be empty.
NotNull.registerCredentials.username = Username field cannot be empty.
Size.registerCredentials.username = Username length must be between 3 and 15 characters.
After that I wanted to replace fixed values min=3 and max=15 with attributes. I tried like that, but it didn't worked (it works in #Size(message="..") annotation):
Size.registerCredentials.username = Username length must be between {min} and {max} characters.
Then I found following code working..:
Size.registerCredentials.username = Username length must be between {1} and {2} characters.
Well.. almost, because it produces following message:
Username length must be between 15 and 3 characters.
Replacing order of these {1} and {2} solves the problem, however it produces confusing code in futher analyze.
Is there a solution to solve this problem with clean code?

Related

Java validation annotation #Pattern with regexp of \\\\ doesn't work properly

I need to do a validation for one of the request fields. I use annotation #Pattern for this.
#Size(min = 3, max = 1000)
#Pattern(regexp = "[0-9A-Za-z\\\\/]+")
private String name;
That is, I must be able to enter the latin letters, numbers, slash and backslash. With this pattern, when I trying to write something like name/\ (looks like "name/\\" in Postman) I get an error
Unexpected internal error near index 6\r\nname/\\
UPDATE:
I did pattern [////]+ and it works! But when I added the alphabet again, the problem came back. I noticed that the stack trace looks different than it does for validation. The error occurs on the following line:
Pattern pattern = Pattern.compile(name, Pattern.CASE_INSENSITIVE);
I use this to check if the same name exists in the MongoDB.

Is quantifiers are required in all the Regex expressions?

I am building a Spring Boot application where input parameters are validated using java.validation.*. I want to check my input parameters for alphabetical characters, numbers and hyphen.
public class Foo {
#NotNull #NotEmpty
#Pattern(regexp = "^[a-zA-Z0-9-]")
private String subscriberType;
#NotNull #NotEmpty
#Size(min = 32, max = 43)
#Pattern(regexp = "^[a-zA-Z0-9-]")
private String caseId;
......
I am using regex as below.
#Pattern(regexp = "^[a-zA-Z]")
If I use above and give input parameters as below,
{
"subscriberType":"prepaid",
"caseId":"5408899645efabf60844de9077372571"
}
I get my validation failed.
Resolving exception from handler [public org.springframework.http.ResponseEntity<java.lang.Object> my.org.presentation.NumberRecycleController.numberRecycle(java.util.Optional<java.lang.String>,my.org.domain.request.NumberRecycleReqDto)
throws java.lang.Exception]: org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 1 in method:
public org.springframework.http.ResponseEntity<java.lang.Object> my.org.presentation.NumberRecycleController.numberRecycle(java.util.Optional<java.lang.String>,my.org.domain.request.NumberRecycleReqDto)
throws java.lang.Exception, with 2 error(s): [Field error in object 'numberRecycleReqDto' on field 'subscriberType': rejected value [prepaid]; codes [Pattern.numberRecycleReqDto.subscriberType,
Pattern.subscriberType,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable:
codes [numberRecycleReqDto.subscriberType,subscriberType]; arguments []; default message [subscriberType],[Ljavax.validation.constraints.Pattern$Flag;#5dcb2ea8,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute#3de9c7b1];
default message [must match "^[a-zA-Z0-9]"]] [Field error in object
'numberRecycleReqDto' on field 'caseId': rejected value [35408899645efabf60844de907737257]; codes [Pattern.numberRecycleReqDto.caseId,Pattern.caseId,Pattern.java.lang.String,Pattern];
arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [numberRecycleReqDto.caseId,caseId]; arguments [];
default message [caseId],[Ljavax.validation.constraints.Pattern$Flag;#5dcb2ea8,org.springframework.validation.beanvalidation.SpringValidatorAdapter$ResolvableAttribute#61637994]; default message [must match "^[a-zA-Z0-9-]"]]
I have gone through some similar questions and found a solution. I can get my validation success if I use my regex as below.
#Pattern(regexp = "^[a-zA-Z0-9-]+"
or
#Pattern(regexp = "^[a-zA-Z0-9-]{1,}"
Can you please explain what actually happens here? I know that quantifiers are looking for given number of matches. In my case 1 or more matches which fall into given pattern.
My question is, giving a quantifier is always required or what? What is the reason for the failure of my initial regex pattern?
The pattern must match the whole string. A character class matches only one character. If the string may contain more than one character, you need the quantifier.
Btw. the ^ at the beginning of the regular expression is redundant. The pattern always must match the whole string.

getText.toString() changes symbols to Unicode

I have a edittext field in my app where end user enters their email for logging in.
When I use getText.toString() to get the value of the field the # symbol is converted automatically to %40 and breaks the passed values to the POST request.
I guess I am missing something simple to stop the auto converting.
I see the issue is with;
#Field(encoded = false, value = "username") String username
A post request parameters get encoded based on the content-type header. You should have your content-type set as "text/html" in order to prevent the encoding.
Alternatively, you can use below code to decode the value as well.
String result = java.net.URLDecoder.decode(receivedStringValue, "UTF-8");
As the server actually requires the field to be "email", worked correctly when I changed the Retro Fit as per below;
//changed value = "username" to value = "email"
#Field(encoded = false, value = "email") String username

How to convert string to MarketDataIncrementalRefresh in QUICKFIX in Java?

I am working on the Stock and Exchange Markets. I have a situation like : I need to take a string from the log and convert it to "Message" type Object. As per this link I have tried using all the three methods of the "MessageUtils" class in JAVA. But my String is being stripped to a Message class type object with unique tags. But as my string is "MarketDataIncrementalRefresh" type I want each every tag to be present in the Message.
For example : I am providing the following string to "MessageUtils.parse()" method.
8=FIX.4.2|9=00795|35=W|49=TT_PRICE|56=SAP0094X|34=2392|52=20170623-04:41:33.375|55=CL|48=00A0HR00CLZ|10455=CLQ7|167=FUT|207=CME|15=USD|262=MDRQ-751|200=201708|18210=1|387=12292|268=24|269=0|290=1|270=4290|271=33|269=0|290=2|270=4289|271=34|269=0|290=3|270=4288|271=40|269=0|290=4|270=4287|271=38|269=0|290=5|270=4286|271=46|269=0|290=6|270=4285|271=53|269=0|290=7|270=4284|271=46|269=0|290=8|270=4283|271=66|269=0|290=9|270=4282|271=48|269=0|290=10|270=4281|271=64|269=1|290=1|270=4291|271=21|269=1|290=2|270=4292|271=40|269=1|290=3|270=4293|271=48|269=1|290=4|270=4294|271=83|269=1|290=5|270=4295|271=62|269=1|290=6|270=4296|271=46|269=1|290=7|270=4297|271=34|269=1|290=8|270=4298|271=55|269=1|290=9|270=4299|271=31|269=1|290=10|270=4300|271=128|269=2|270=4291|271=1|269=4|270=4280|269=7|270=4292|269=8|270=4277|10=044|
But what I am getting is this:
8=FIX.4.2|9=192|35=W|34=2|49=TT_PRICE|52=20170622-14:16:23.685|56=SAP0094X|15=USD|48=00A0HR00GCZ|55=GC|167=FUT|200=201708|207=CME|262=MDRQ-21|268=25|269=0|270=12510|271=24|290=1|387=121890|10455=GCQ7|18210=1|10=036|
As you can observe only unique tags are present in the String. But I want each and every tag , no matter how many times it exists in the provided string.
Please can anyone help me doing this in JAVA. It will be really appreciable.
Below is the code I am using for converting :
MessageUtils mu = new MessageUtils();
Session session = Session.lookupSession(sessionID);
Message msg = MessageUtils.parse(new DefaultMessageFactory(), null, str);
// Message msg = new Message(str, false); //This can also be used for converting
System.out.println(msg.toString());
The other thread says:
MessageUtils.parse(MessageFactory messageFactory, DataDictionary dataDictionary, java.lang.String messageString)
And your code says:
Message msg = MessageUtils.parse(new DefaultMessageFactory(), null, str);
So you need to fix your data dictionary and pass it to the parse method instead of passing 'null'
I think the problem is as follows. There's a repeating group that starts with tag 286 (NoMDEntries). The order of fields in a repeating group should be strict, i.e. the same order as the definition of the repeating group. See Market Data - Snapshot/Full Refresh or the data dictionnary supplied by QuickFIX/J (FIX42.xml).
The 268 tag should be followed by 269 and then 270. I am seeing in your message string: |268=24|269=0|290=1|270=4290| which is the incorrect order of tags. That is probably the reason why the message is truncated by MessageUtils.parse.
As a test you could try to manually correct the order in the string and try parsing that to see if that gives the correct message.

Setting a character limit for a string using Java annotations

I'm trying to create a string with a character length restriction of 12 for my JBOSS Seam project. The string must either be 12 characters or blank. My length annotation is correct which is the following:
#Length(min = 12,max = 12)
However when I try to put a null value in there I get an InvalidStateException: validation fail error. Any ideas how to allow this?
Null value for String and empty String are not the same thing. You are passing a null value (not a String of length 0). Check this out:
Difference between null and empty ("") Java String
Also, you should try out #Size(min=,max=).
Well I decided to not rely on the #Length annotation and instead created my own custom validator class to do the job and that worked out well. Thanks anyway!

Categories