Tomcat say: No payload parameter on [OnMessage] method - websocket

the error stack
My annotation at ServerEndPoint:
#ServerEndpoint(value = "/portal/{action}/{num}/{msg}", configurator = GetHttpSessionConfigurator.class)
My annotation at onMessage method:
#OnMessage
public void onMessage(#PathParam("action") String action, #PathParam("num") String num, #PathParam("msg") String msg, Session session)

I know. It is necessary to add a parameter to receive the other message. So just remove the third annotation of the parameter of the [Method] annotated by #OnMethod.

Related

Is it possible to trigger validations when calling RestController method from outside?

So far I've got an endpoint which goes as follows:
#PostMapping(path = "/my-endpoint")
public ResponseEntity<Void> method(#PathVariable("id") String id,
#RequestBody #Valid MyClass<MyType> body) {
// custom logic in here
return ResponseEntity.ok().build();
}
When performing the POST request to that endpoint, the validation when the object is wrong is performed properly and 400: Bad Request is shown.
However, now due to some code circumstances I want to trigger that method from outside the RestController and perform the same validations via a Consumer.
The new code goes as follows:
#Bean
public Consumer<Message<String>> consumer(MyController myController) {
message -> myController.method("sampleId", message); // message here is parsed to the class, so the proper type is sent to the controller method.
}
And whenever I check for the myController.method call, the code is always 200: OK, no matter what input is sent.
Is there a way to trigger validations not sent through the REST API?
I suggest to move custom logic from controller to a #Service annotated class first.
Then inject validator #Autowired private Validator validator; and trigger validation.
public void myServiceMethod(MyMessage message) {
Set<ConstraintViolation<MyMessage>> violations = validator.validate(message);
if (!violations.isEmpty()) {
// ...
}
}
https://www.baeldung.com/spring-service-layer-validation

Spring Validation Errors for RequestParam

I want to pass org.springframework.validation.Errors to CodeValidator class.
But, since I am not using RequestBody/RequestPart/ModelAttribute, I cannot put Errors in method param after variable.
I use #RequestParam for code variable, and I want to validate that using CodeValidator class that implement org.springframework.validation.Validator.
Here is my code
#RequestMapping(value = "/check-code", method = RequestMethod.POST)
public ResponseEntity<Object> checkCode(#RequestParam("code") String code, Errors errors) {
codeValidator.validate(code, errors);
if(errors.hasErrors()) {
return ResponseEntity.badRequest().body("Errors");
}
return ResponseEntity.ok("");
}
and here error result for my code:
An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the #RequestBody or the #RequestPart arguments to which they apply: public org.springframework.http.ResponseEntity com.example.myapp.controller.CodeController.checkCode(java.lang.String,org.springframework.validation.BindingResult)
what should I do to be able using CodeValidator with #RequestParam?
Updated:
Code for CodeValidator
#Service
public class CodeValidator implements Validator {
#Override
public void validate(Object target, Errors errors) {
String code = ((String) target);
if(code == null || code.isEmpty()) {
errors.rejectValue("code", "", "Please fill in Code.");
}
}
}
Did you create an annotation with your validator?
Otherwise take a look at a small example/tutorial for custom validating with spring: https://www.baeldung.com/spring-mvc-custom-validator
(edit) if you are using spring boot you might need add a MethodValidationPostProcessor bean to your spring config to enable custom valdation for the #requesParam

In Spring 5, how do I customize a form validation error message?

I'm using Spring 5.1. I want to write a validator for a form I'm submitting and I would like to customize one of the error messages that comes back. I have the error message stored in a properties file ...
already.taken.registration.username=There is already an account created with the username {0}. Did you forget your password?
Note the "{0}" for where I would like to insert the invalid username the user has entered. So in my validator I have
import org.springframework.validation.Validator;
...
public class RegistrationFormValidator implements Validator
{
...
#Override
public void validate(final Object target, final Errors errors)
{
final RegistrationForm regForm = (RegistrationForm) target;
if (regForm != null &&
!StringUtils.isEmpty(regForm.getEmail()) &&
userWithEmail(regForm.getEmail()) ) {
errors.rejectValue("email", "already.taken.registration.username", regForm.getEmail());
} // if
However, when the specific branch is run, the {0} isn't getting populated, despite the fact I've verified that "regForm.getEmail()" is non-empty. I see this printed to my JSP page
There is already an account created with the username {0}. Did you forget your password?
What's the correct way to fill in the error message with custom data?
errors.rejectValue("email", "already.taken.registration.username", regForm.getEmail());
This will actually call the method
void rejectValue(#Nullable
java.lang.String field,
java.lang.String errorCode,
java.lang.String defaultMessage)
What you need is to add an array of objects with the arguments:
void rejectValue(#Nullable
java.lang.String field,
java.lang.String errorCode,
#Nullable
java.lang.Object[] errorArgs,
#Nullable
java.lang.String defaultMessage)
Your call will be something like this :
errors.rejectValue("email", "already.taken.registration.username", new Object[] {regForm.getEmail()}, null);

#SpyBean and Mockito.any() during verify

I'm experiencing following problem. I've got a spring boot test, where I inject and spy the mongoDbChannel bean. Then I try to start the normal workflow and verify if the method send is called on the bean.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {MongoAsBackupConfig.class},
properties = {},
webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MongoAsBackupConfigTest {
#SpyBean(name = "mongoDbChannel")
private QueueChannel mongoDbChannel;
#Autowired
private DirectChannel mongoDbWithFailoverChannel;
#DirtiesContext
#Test
public void shouldUseFallbackForFullQueue() throws InterruptedException {
IntStream.rangeClosed(1, BACKUP_QUEUE_CAPACITY + OVERFILLING_CLICK_COUNT).forEach(someNumber ->
mongoDbWithFailoverChannel.send(MessageBuilder.withPayload(createPayload(someNumber)).build()));
verify(mongoDbChannel, times(BACKUP_QUEUE_CAPACITY)).send(Mockito.any());
}
}
As a result, I get the error message that any doesn't match to the concrete parameter value. However normally any means any value of param. What went wrong here?
Argument(s) are different! Wanted:
mongoDbChannel.send(
<any>
);
-> at MongoAsBackupConfigTest.shouldUseFallbackForFullQueue(MongoAsBackupConfigTest.java:67)
Actual invocation has different arguments:
mongoDbChannel.send(
GenericMessage [payload=Click(...), headers={id=0eaa2317-b1b5-604d-65c5-78da521cd585, timestamp=1509085945379}],
10
);
-> at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
EDITED:
I'm using java 8. And I tried to use any(GenericMessage.class), any(Message.class) but it was the same effect.
I assume you are using java 8 which means that when using Mockito.any(), the compiler will infer the type that has to be used based on the parameter type in the signature of send method.
That seems to be Message based on the method definition : send(Message<?> message)
What is actually passed is an instance of GenericMessage.
As I assume GenericMessage extends Message, then you can write your verify as follows:
verify(mongoDbChannel, times(BACKUP_QUEUE_CAPACITY))
.send(Mockito.any(GenericMessage.class));
Update
There also seems to be an overloaded method send(Message<?> message, long timeout). Maybe this version gets called instead of the single arg one..

Spring Custom Annotation Solver MulitpartFile Resolves to Null

I have a Spring custom annotation which I am using instead of #requestParam
public Response uploadImages(#myResolver(value = "imageFile", required = true) final MultipartFile multiPartFile) {...}
However, the mulitpart file parameter is resolved to null. So I put a breakpoint in my HandlerMethodArgumentResolver.resolveArgument to see if the argument was being resolved, but the breakpoint is never reached. But I know my custom annotation works for other params such as String, long e.t.c.
When I try using #requestParam instead it works fine, and the multipart file is resolved.
public Response uploadImages(#requestParam(value = "imageFile", required = true) final MultipartFile multiPartFile) {...}
Does anyone know why mulitpart file is being resolved to null using my custom parameter resolver and not using resolveArgument and how I could solve this please?
Thanks!
EDIT
The config for adding argument resolvers
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
super.addArgumentResolvers(argumentResolvers);
argumentResolvers.add(new MyAnnotationResolver());
}
My annotation definition
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
#Component
public #interface MyResolver{
String value() default "";
boolean required() default true;
String defaultValue() default ValueConstants.DEFAULT_NONE;
String errorCode() default "40000";

Resources