Access to pre-interpolated bean validation message template in SpringMVC? - spring

I'm using Spring Validation within a Spring MVC application that delegates validation to Hibernate Validator 5. I'm successfully able to have beans validated and have the messages interpolated by the validator. However, it's important that I also be able to have access to the message template itself, pre-interpolation.
For example, in some bean I have validation #Size(min=5,max=15,message="{my.custom.message}". In a messages.properties file I have entry my.custom.message=test min {min} and max {max}. In my BindingResult, I see the ObjectError with error message "test min 5 and max 15", but I need to look a value up at this point based on the non-interpolated my.custom.message raw value.
Can this be done? If it can't out of the box, can someone point me in the right direction for how I might customize spring's LocalValidatorFactoryBean to preserve this?
Update
I'm looking at extending org.springframework.validation.beanvalidation.SpringValidatorAdapter, and wrapping the getArgumentsForConstraint to automatically append the pre-interpolated message to the returned list of arguments. The notion of exactly what these 'arguments' are and how they're used is unclear to me, but if it's purely used for message interpolation, it seems relatively safe for me to append at the end. Any reason this might not work? Problems it might cause? Better ideas?
Solution
Didn't find any great solutions other than my 'update' above, so I ended up subclassing LocalValidatorFactoryBean with this:
#Override
protected Object[] getArgumentsForConstraint(String objectName, String field, ConstraintDescriptor<?> descriptor) {
if (null == descriptor) return super.getArgumentsForConstraint(objectName, field, descriptor);
Object[] orig = super.getArgumentsForConstraint(objectName, field, descriptor);
if (null == orig || orig.length < 1) return new Object[] { descriptor };
Object[] retval = new Object[orig.length+1];
System.arraycopy(orig, 0, retval, 0, orig.length);
retval[retval.length-1] = descriptor;
return retval;
}
In subsequent code, I look at the last object in this array and test to see if it's an instance of ConstraintDescriptor. Good enough I suppose.

However, it's important that I also be able to have access to the message template itself, pre-interpolation.
In which context do you need to access the template? If it is after validation, then getMessageTemplate() on ConstraintViolation gives you this. If it is within a constraint validator implementation, then you could use getDefaultConstraintMessageTemplate() on ConstraintValidatorContext.

Related

Spring-AOP Return value of Aspect #AfterReturn is not working

#AfterReturning(value = "anyPublicMethod() && applyPrivacy()", returning = "result")
public Object afterReturning(JoinPoint joinPoint, Object result) {
return someService.createNewObjectWithHelpOfResult(result);
}
My intention was to fill some null values in result fields. So in method createNewObjectWithHelpOfResult I'm creating a new Object and setting only the required values. But return value is not reflecting after afterReturning method is finished. But if I do mutations on result. They're very well reflected after aspect #AfterReturning method ends, but I want the return value to be used? Is this not possible? I'll have to do mutation only?
What #M.Deinum explained, is documented in the Spring manual, section "After Returning Advice". The end of the section reads:
Please note that it is not possible to return a totally different reference when using after returning advice.
Therefore, you cannot just make your #AfterReturning advice have a return type other than void and hope it will magically return something. As the advice type name implies, all 3 types of #After* advices run after the method has returned already. There is nothing you can do to change the result (except for altering internal state of an object instance). You can merely read (and e.g. log) it.
The solution, like #M.Deinum said, is an #Around advice, see also again the Spring manual.
It is generally a good idea to at least study the manual and learn some basics or take a look at examples before asking questions in public. I am sure you did not find any valid example for an #After* advice with non-void return type.
I am using #AfterReturning on the methods whose return type is String but instead of String I am getting null as result
#AfterReturning(value = "execution(* com.example.demo.aop.business..(..))", returning = "result")
public void afterA(JoinPoint joinPoint, Object result) {
log.info("After method {} returned with value {}", joinPoint, result);
}
O/P - After method execution(void com.example.demo.aop.business.Business2.disp()) returned with value null

SQS Listener #Headers getting body content instead of Message Attributes

I am using Spring Cloud SQS messaging for listening to a specified queue. Hence using #SqsListener annotation as below:
#SqsListener(value = "${QUEUE}", deletionPolicy = SqsMessageDeletionPolicy.ALWAYS )
public void receive(#Headers Map<String, String> header, #Payload String message) {
try {
logger.logInfo("Message payload is: "+message);
logger.logInfo("Header from SQS is: "+header);
if(<Some condition>){
//Dequeue the message once message is processed successfully
awsSQSAsync.deleteMessage(header.get(LOOKUP_DESTINATION), header.get(RECEIPT_HANDLE));
}else{
logger.logInfo("Message with header: " + header + " FAILED to process");
logger.logError(FLEX_TH_SQS001);
}
} catch (Exception e) {
logger.logError(FLEX_TH_SQS001, e);
}
}
I am able to connect the specified queue successfully and read the message as well. I am setting a message attribute as "Key1" = "Value1" along with message in aws console before sending the message. Following is the message body:
{
"service": "ecsservice"
}
I am expecting "header" to receive a Map of all the message attributes along with the one i.e. Key1 and Value1. But what I am receiving is:
{service=ecsservice} as the populated map.
That means payload/body of message is coming as part of header, although body is coming correctly.
I wonder what mistake I am doing due to which #Header header is not getting correct message attributes.
Seeking expert advice.
-PC
I faced the same issue in one of my spring projects.
The issue for me was, SQS configuration of QueueMessageHandlerFactory with Setting setArgumentResolvers.
By default, the first argument resolver in spring is PayloadArgumentResolver.
with following behavior
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (parameter.hasParameterAnnotation(Payload.class) || this.useDefaultResolution);
}
Here, this.useDefaultResolution is by default set to true – which means any parameter can be converted to Payload.
And Spring tries to match your method actual parameters with one of the resolvers, (first is PayloadArgumentResolver) - Indeed it will try to convert all the parameters to Payload.
Source code from Spring:
#Nullable
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
if (result == null) {
for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
if (resolver.supportsParameter(parameter)) {
result = resolver;
this.argumentResolverCache.put(parameter, result);
break;
}
}
}
return result;
}
How I solved this,
The overriding default behavior of Spring resolver
factory.setArgumentResolvers(
listOf(
new PayloadArgumentResolver(converter, null, false),
new HeaderMethodArgumentResolver(null, null)
)
)
Where I set, default flag to false and spring will try to convert to payload only if there is annotation on parameter.
Hope this will help.
Apart from #SqsListener, you need to add #MessageMapping to the method. This annotation will helps to resolve method arguments.
I had this issue working out of a rather large codebase. It turned out that a HandlerMethodArgumentResolver was being added to the list of resolvers that are used to basically parse the message into the parameters. In my case it was the PayloadArgumentResolver, which usually always resolves an argument to be the payload regardless of the annotation. It seems by default it's supposed to come last in the list but because of the code I didn't know about, it ended up being added to the front.
Anyway, if you're not sure take a look around your code and see if you're doing anything regarding spring's QueueMessageHandler or HandlerMethodArgumentResolver.
It helped me to use a debugger and look at HandlerMethodArgumentResolver.resolveArgument method to start tracing what happens.
P.S. I think your #SqsListener code looks fine except that I think #Headers is supposed to technically resolve to a Map of < String, Object >", but I'm not sure that would cause the issue you're seeing.

Spring REST and PATCH method

I'm using SpringBoot and Spring REST.
I would like to understand the HTTP PATCH method to update properties of my Model
Is there any good tutorial explaining how to make it works ?
HTTP PATCH method and body to be Send
Controller method and how to manage the update operation
I've noticed that many of the provided answers are all JSON patching or incomplete answers. Below is a full explanation and example of what you need with functioning real world code
First, PATCH is a selective PUT. You use it to update any number of fields for an object or list of objects. In a PUT you typically send the entire object with whatever updates.
PATCH /object/7
{
"objId":7,
"objName": "New name"
}
PUT /object/7
{
"objId":7,
"objName": "New name",
"objectUpdates": true,
"objectStatus": "ongoing",
"scoring": null,
"objectChildren":[
{
"childId": 1
},
............
}
This allows you to update records without huge amounts of endpoints. For example, with above, to update scoring you need object/{id}/scoring, then to update name you need object/{id}/name. Literally one endpoint for every item or you require the front end to post the entire object for every update. If you have a huge object, this can take a lot of network time or mobile data that is unnecessary. The patch lets you have 1 endpoint with the minimal object property sends that a mobile platform should use.
here is an example of a real world use for patch:
#ApiOperation(value = "Patch an existing claim with partial update")
#RequestMapping(value = CLAIMS_V1 + "/{claimId}", method = RequestMethod.PATCH)
ResponseEntity<Claim> patchClaim(#PathVariable Long claimId, #RequestBody Map<String, Object> fields) {
// Sanitize and validate the data
if (claimId <= 0 || fields == null || fields.isEmpty() || !fields.get("claimId").equals(claimId)){
return new ResponseEntity<>(HttpStatus.BAD_REQUEST); // 400 Invalid claim object received or invalid id or id does not match object
}
Claim claim = claimService.get(claimId);
// Does the object exist?
if( claim == null){
return new ResponseEntity<>(HttpStatus.NOT_FOUND); // 404 Claim object does not exist
}
// Remove id from request, we don't ever want to change the id.
// This is not necessary, you can just do it to save time on the reflection
// loop used below since we checked the id above
fields.remove("claimId");
fields.forEach((k, v) -> {
// use reflection to get field k on object and set it to value v
// Change Claim.class to whatver your object is: Object.class
Field field = ReflectionUtils.findField(Claim.class, k); // find field in the object class
field.setAccessible(true);
ReflectionUtils.setField(field, claim, v); // set given field for defined object to value V
});
claimService.saveOrUpdate(claim);
return new ResponseEntity<>(claim, HttpStatus.OK);
}
The above can be confusing for some people as newer devs don't normally deal with reflection like that. Basically, whatever you pass this function in the body, it will find the associated claim using the given ID, then ONLY update the fields you pass in as a key value pair.
Example body:
PATCH /claims/7
{
"claimId":7,
"claimTypeId": 1,
"claimStatus": null
}
The above will update claimTypeId and claimStatus to the given values for claim 7, leaving all other values untouched.
So the return would be something like:
{
"claimId": 7,
"claimSrcAcctId": 12345678,
"claimTypeId": 1,
"claimDescription": "The vehicle is damaged beyond repair",
"claimDateSubmitted": "2019-01-11 17:43:43",
"claimStatus": null,
"claimDateUpdated": "2019-04-09 13:43:07",
"claimAcctAddress": "123 Sesame St, Charlotte, NC 28282",
"claimContactName": "Steve Smith",
"claimContactPhone": "777-555-1111",
"claimContactEmail": "steve.smith#domain.com",
"claimWitness": true,
"claimWitnessFirstName": "Stan",
"claimWitnessLastName": "Smith",
"claimWitnessPhone": "777-777-7777",
"claimDate": "2019-01-11 17:43:43",
"claimDateEnd": "2019-01-11 12:43:43",
"claimInvestigation": null,
"scoring": null
}
As you can see, the full object would come back without changing any data other than what you want to change. I know there is a bit of repetition in the explanation here, I just wanted to outline it clearly.
There is nothing inherently different in PATCH method as far as Spring is concerned from PUT and POST. The challenge is what you pass in your PATCH request and how you map the data in the Controller. If you map to your value bean using #RequestBody, you'll have to figure what is actually set and what null values mean. Others options would be limit PATCH requests to one property and specify it in url or map the values to a Map.
See also Spring MVC PATCH method: partial updates
Create a rest template using -
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
RestTemplate rest = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
now make the PATCH call
ResponseEntity<Map<String, Object>> response = rest.exchange(api, HttpMethod.PATCH, request,
responseType);

JSF: how to replace standard Required Validator

I have a lot of code with standard required validation.
Something like this
<h:inputText required="true" requiredMessage="it is required!"/>
Now, I need to change behavior of RequiredValidator: put error message to the context, but do not interrupt cycle. May be to do something more.
I tried to add custom validator with the same id, but it did not work.
<validator>
<validator-id>javax.faces.Required</validator-id>
<validator-class>my.RequiredValidator</validator-class>
</validator>
Is it possible?
Empty fields are not committed to validators. I could not find a matching documentation, but I tested the environment and please take a look at Get empty strings from <h:inputText> go through validation.
This question also handles an empty string input and BalusC says:
JSF 1.x does by default not fire validators on empty fields.
OK, it's about JSF 1.X, but it seems it didn't change.
Validators are to interrupt the request, but that's not what you want. So could it be a workaround to use the setter method for your needs?
Ommit the required attribute from your inputText and add a FacesMessage in the setter for your textInput. Assumed the assingned value is #{myBean.description}, the setter may look like this:
public void setDescription(String value) {
String _tmp = value.trim();
if (_tmp.equals("")) {
FacesContext ctx = FacesContext.getCurrentInstance();
ctx.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR
, "Error:", "Input must not be empty"));
this.description = null;
return;
}
this.description = _tmp;
}

how to do validation with not well form XML while doing unmarshalling?

I have an unmarshaller along with an MySchema.xsd file.
StreamSource sources = new StreamSource(getClass().getClassLoader().getResourceAsStream("/xmlValidation.xsd"));
SchemaFactory sf = SchemaFactory.newInstance( XMLConstants.W3C_XML_SCHEMA_NS_URI );
unmarshaller.setSchema(sf.newSchema(sources));
And make a call to unmarshaller.setEventHandler() function, to specify a custom validation event handler, which basically format a error tips string , by:
final String errorString = new String();
unmarshaller.setEventHandler(new ValidationEventHandler() {
#Override
public boolean handleEvent(ValidationEvent validationevent) {
if(validationevent.getSeverity()!= ValidationEvent.WARNING){
errorString.format( "Line:Col[" + validationevent.getLocator().getLineNumber()
+ ":" + validationevent.getLocator().getColumnNumber()
+ "]:" + validationevent.getMessage());
return false;
}
return true;
}
});
The above codes seem work ok(I can get java object when the input string is validated. and also the error tips string is formated as excepted)
The problem is that, when the input xml is not well form, it also throw a SaxParseException.
Thanks in advance.
Andrew
Well formed relates to the XML syntax itself, as opposed to being valid WRT an XML schema:
http://en.wikipedia.org/wiki/Well-formed_element
If you have XML that is not well formed then you will get a ValidationEvent.FATAL_ERROR and unmarshalling will not be able to continue, as the underlying parser used by JAXB cannot continue.
For more information:
http://bdoughan.blogspot.com/2010/12/jaxb-and-marshalunmarshal-schema.html
K, I mess up something and get this problem.
Now I figure it out. If I am wrong, please point me out. below it's what I find in javadoc and test on my project:
javax.xml.bind.ValidationEventHandler can handler the constrain error with the given schema constrains, when unmarshaller is unmarshaling.
unmarshaller.unmarshal(xmlInputStream);
The ValidationEventHandler will be called during the unmarshaling process if error occurs.
The SAXEception will be thrown, if the xmlInputStream is not well form.
And I cant find a way to catch the SAXException, throw by the sax parser, so I guess using validation during unmarshaling can't due with un-well form xml string.
I use javax.xml.validation.Validator to validate that the xml string is well form and under constrain.
jaxbValidator.validate(xmlSource);
The above code will throw SAXException.
If no exception is thrown, then unmarshall the xml string into object.

Resources