So, I got into this new Spring Boot project which was already under developement and while writing API's I used Enum for #RequestParam in my controller and it worked.
I did not write any converters for this.
Later on I noticed that in this project the other developers had written custom Converter's for this.
So I decided to search the web regarding this and all solutions that came up for using Enum with Controller in Spring Boot used converter, could not find any examples without converter like how I did.
Below is one an example of how I wrote this, LoanStatus is an Enum:
#RequestMapping(value = "/loans", method = RequestMethod.GET)
public ResponseEntity<?> getPatientsLoan(HttpServletRequest request,
#RequestParam(value = "loanStatus", required = false) LoanStatus loanStatus) {}
So is this a relatively new feature that Spring Boot accepts Enums now without the need for converter's and that is why all the examples used converters or will I face some issue in feature cause I did not user converter's even though it is currently working for me?
Spring has supported String to Enum conversion since Spring 3.0. There is a ConverterFactory which dynamically creates a converter for the specific enum.
Prior to that you would need to write a custom Converter or PropertyEditor to convert enums. But basicallly with the current versions you don't need to if the String matches the Enum name.
If you want custom enum conversion (by some internal value or whatever) you still would need a custom converter.
Related
How can we force developer to write Developed Custom-annotation on rest api
Example :
We Developed annotation Called : ValidatePermission
what we need to do , displaying runtime error for developer that he missing annotation #ValidatePermission on API , when he tried to write new api
#ValidatePermission
#GetMapping("/details")
#PreAuthorize("hasAuthority('902')")
public ResponseEntity<CustDtlsInqDto> getCustomerDetails(#CurrentUser UserPrincipal currentUser,
#RequestParam(name = "poiNumber", required = false) String poiNumber,
#RequestParam(name = "cif", required = false) String cif) {
return ResponseEntity.ok(customerService.getCustomerDetailsByPoiOrCif(currentUser.getId(), poiNumber, cif));
}
Annotations usage cannot be forced in any way before or on compilation (at least I am not aware of any technique, feel free to correct me).
The only way to go is to perform a check-up during the unit testing phase. Simply write an unit test that scans through the REST API definition beans and its public methods (or annotated) to check up using teh Reflection API whether an annotation from a particular category (implementation details up to you) is present within the formal parameters of methods.
Gits Github: Find all annotated classes in a package using Spring
Baeldung: A Guide to the Reflections Library
Something looks to me weird in this approach.
So you say:
...displaying runtime error for developer that he missing annotation #ValidatePermission on API
Based on this phrase, let me suggest an alternative:
So the developer that runs the project locally (during the debugging session or maybe tests) should see an error if he/she didn't put the annotation on the methods of rest controller, right?
If so, Why don't you need the developers to put this annotation?
The main idea of my suggestion is: Why not letting spring to do it for you automatically?
You could implement some kind of aspect or if you don't want to use a spring aop and prefer 'raw plain spring', BeanPostProcessor, that would 'wrap' all the methods of class annotated with RestContoller (by creating a run-time proxy) and before running a controller method will executed the logic that was supposed to be supported by the annotation?
In the case of Web MVC, another approach is to implement an interceptor that will be invoked automatically by spring mvc engine and you'll be able to execute any custom logic you want there, you'll also be able to inject other beans (like auxiliary services) into the interceptor.
Read this article in case you're not familiar with these interceptors, you'll need preHandle methods as far as I understand.
I use Spring Boot and Hibernate validator and Thymeleaf.
Everything is ok when I validate a form item.
But after I add a verify code, I check if it's wrong code;
When the code is wrong I add a new FieldError and return it.
if (!captchaCode.equalsIgnoreCase(user.getVrifyCode())) {
bindingResult.addError(new FieldError("user", "vrifyCode", "{singup.vrifycode.error}"));
}
And of course I defined the singup.vrifycode.error in my ValidationMessages.properties file.
But at web page it just show singup.vrifycode.error not the correct value.
But in my model everything is ok like this:
#NotBlank(message="{signup.email.null}")
#Email(message="{signup.email.fomart}")
private String email;
How can I show correct value in my page?
If I can not, tell me how can I get the correct value(by locale) in ValidationMessages_en_US.properties, ValidationMessages_ja_JP.properties and so on.
Thanks!
First we must understand that there are two different validations API:s in the mix here; first the Spring validation with BindingResult and FieldError classes, and then the Bean Validation API (Hibernate Validator) with the annotations. The good news is that Spring translates validation errors from Bean Validation API, so these work together.
One difference is that Spring doesn't use { and } around its translation keys (in spring called codes), keep that in mind.
For i18n you must use the 7-arguments constructor of FieldError:
new FieldError("user", "vrifyCode", user.getVrifyCode(), false, new String[] {"singup.vrifycode.error"}, null, null)
Note that the translation should be in the Spring messages file, because it is Spring validation we are working with here.
I am currently working on a web project which is using Play Framework 2.1.0. Play supports a decent API for parsing form data and mapping that to the Model beans directly. Which looks something like,
Form<Employee> form = Form.form(Employee.class).bindFromRequest();
if (form.hasErrors()) {
return badRequest(template.render(form));
}
This API also does validations on the fly and is capable of handling binding failures, when say a String could not be converted to an Integer. The Form API keeps the collection of errors mapped to the name of the property. Underlying the Form API, Play is using DataBinder of Spring's validation framework which is actually doing all the magic.
I was wondering if there is similar binding API to convert from JSON to the bean directly, with support for handling binding failures?
Play 2.0 uses Jackson internally which fails when there are binding failures and simply throws an exception. I looked at the code and does not look easy to supress these errors.
Is there some framework that can satisfy my requirement out of the box?
Essentially, I need the framework to convert from JSON to Java Bean, which can handle binding failures gracefully.
It would be wonderful if it allows me to collect them somewhere so I can generate appropriate validation errors. I will run custom validations on the parsed object using javax.validation APIs to perform more specific validations once the JSON is parsed into the Bean.
I achieved this by adding custom deserializers in Jackson
SimpleDeserializers deserializers = new SimpleDeserializers();
deserializers.addDeserializer(Integer.class, new MyIntegerDeserializer(null));
deserializers.addDeserializer(Long.class, new MyLongDeserializer(null));
ObjectMapper mapper = new ObjectMapper().setDeserializerProvider(
new StdDeserializerProvider().withAdditionalDeserializers(deserializers));
MyModel value = mapper.treeToValue(node, MyModel.class);
MyIntegerDeserializer and MyLongDeserializer are custom deserializers for Integer and Long values respectively. These are in my case exact copy of the internal default corresponding deserializer classes with additional code to gracefully handle NumberFormatException
I have a Spring MVC controller which is servicing GET requests, to perform a search.
These requests have many optional parameters which may be passed on the query string.
For example:
#Data
public class SimpleSearchRequest implements SearchRequest {
private String term;
private List<Status> stati;
#JsonDeserialize(using=DateRangeDeserializer.class)
private Range<DateTime> dateRange;
}
If I were using a POST or PUT for this, I could nicely marshall the inbound request using a #RequestBody. However, because I'm using a GET, this doesn't seem to fit.
Instead, it seems I'm required to list all the possible parameters on the method signature as #RequestParam(required=false).
Aside from leading to ugly method signatures, I'm also losing out on all sorts of OO goodness by not using classes here.
Attempting to use #RequestBody fails (understandably so), and as discussed here and here, using an actual request body on a GET is not desirable.
Is there a way to get Spring MVC to support marshalling multiple #RequestParam's to a strongly typed object on GET requests?
It seems the answer was to simply remove the annotation.
This worked:
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Result> search(SearchRequest request) {}
I have classic Spring MVC application.
I want to validate a Form using a corresponding Java Bean, annotated with JSR-303 validation annotation.
The form data is sent by an ajax call using JSON. This Json is converted to the target Java Bean with Jackson - automatically by spring:
#RequestMapping(value = ControllerConstants.CALCULATION_MAPPING_SUBMIT_FORM,method = RequestMethod.POST)
public String submitForm(#Valid #RequestBody MyFormBean bean, final BindingResult result) {
...
}
Problem is for example if I have an Integer field in my bean but, in JSON the values is not a number. In this case it cannot create the target bean, that cannot be validated. This situation cannot be solved with custom property editors, since there is no way to convert a a text that not represents an Integer to Integer.
It seems that this is solved in Grails, we get errors from validator (errors is domain object) which has to be created during the data binding. So I assume spring supports this, thus Grails just uses Spring's support)
So how to elegantly solve this situation to handle this "validation" error?
UPDATE
Actually I figured out, that is this is supported by spring if we use simple form submit. The problem is with integration of Jackson deserialized. It does not fills errors. Still how to solve this?
I see two options...
Have client side validation that would not allow the form to be submitted if the there are formatting issues.
On the server side you will have to have a mechanism of handling the exception that would catch it and report the problem back to client.
Hope that helps.
EDIT:
Well not having client side validations may not be a good user experience. Users do not want to be reminded about validation errors after they have made a server round trip. However, if this is still a constraint have a look at following url and it gives elegant way of handling such issues and reporting informative error messages.
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/