I am using Spring Boot 2. I want to add certain dynamic validations at server side which should be executed in POST REST call. Can these validations be added in form of annotations at parameter level of POST method call?
Below code will help you to achieve server side validation.
Pojo class :
public class Data {
#NotNull
private final String someStringValue;
#Min(1)
private final int someIntValue;
#JsonCreator
public Data(#JsonProperty("someStringValue") String someStringValue, #JsonProperty("someIntValue") int someIntValue) {
this.someStringValue = someStringValue;
this.someIntValue = someIntValue;
}
public String getSomeStringValue() {
return someStringValue;
}
public int getSomeIntValue() {
return someIntValue;
}
For the validation we need a custom class containing the logic:
#Component
public class StringValueValidator {
public void validate(String language, Data data, Errors errors) {
if (!"de-DE".equals(language)) {
if (data.getSomeStringValue().length() > 140) {
errors.reject("someStringValue");
}
}
}
}
controller method :
#RequestMapping(value = "/validation", method = RequestMethod.POST)
public ResponseEntity<?> acceptData(#Valid #RequestBody Data data, Errors errors,
#RequestHeader(HttpHeaders.ACCEPT_LANGUAGE) String language) {
stringValueValidator.validate(language, data, errors);
if (errors.hasErrors()) {
return new ResponseEntity<>(createErrorString(errors), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.OK);
}
Refer this : https://blog.codecentric.de/en/2017/11/dynamic-validation-spring-boot-validation/
Here is how you can achieve to defining validations in RequestBody you are receiving from client side.
Define your POJO you will receive from client side.
public class Employee implements Serializable {
private Long id;
#NotNull(message = "Name should not be null")
#NotBlank(message = "Name should be not empty")
#Size(min = 1, max = 255, message = "Name allowed max 255 characters")
private String name;
Now in your controller use #Valid annotation for #RequestBody like below.
public ResponseEntity<?> createEmployee(#Valid #RequestBody Employee employee)
Related
I have problem with CRUD edit operation. When i click Edit which is written in this way in jsp file
Edit
i got error
HTTP Status 404 – Not Found
Type Status Report
Message /Firstaidkit/editMedicines
Description The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
EditController
#WebServlet(value = "/editMedicines")
public class MedicinesEditController extends HttpServlet {
private static final long serialVersionUID = 1L;
#RequestMapping(method = RequestMethod.GET)
public ModelAndView editMedicines(HttpServletRequest request) {
int medicinesId = Integer.parseInt(request.getParameter("id"));
Medicines medicines = GenericDAO.get(medicinesId);
ModelAndView model = new ModelAndView("editform");
model.addObject("medicines", medicines);
return model;
}
}
GenericDAO
public interface GenericDAO <T, PK extends Serializable> {
//CRUD
T create(T newObject);
T read(PK primaryKey);
public void update(Medicines medicines);
public void delete(T id);
List<T> getAll();
public static Medicines get(int medicinesId) {
return null;
}
}
MedicinesDAOImpl
private final static String UPDATE_MEDICINES =
"UPDATE medicines SET name=:name, drugform=:drugform, quantity=:quantity, expiration_date=:expiration_date, description=:description WHERE id_medicines=:id_medicines;";
#Override
public void update(Medicines medicines) {
jdbcTemplate.update(UPDATE_MEDICINES, medicines.getName(), medicines.getDrugForm(),
medicines.getQuantity(), medicines.getExpirationDate(), medicines.getId());
}
}
editform.jsp
<form class="form-signin" method="post" action="editMedicines">
I believe the problem is that the URL your anchor is linked to does not exist. You should have an annotation dictating the path on your MedicinesEditController at a class level. Assuming you want the path of this endpoint to be /Firstaidkit/editMedicines, the following should work:
#Path(value = "/Firstaidkit") // possibly a different but similar annotation
public class MedicinesEditController extends HttpServlet {
#RequestMapping(value = "/editMedicines", method = RequestMethod.GET)
public ModelAndView editMedicines(HttpServletRequest request) {
int medicinesId = Integer.parseInt(request.getParameter("id"));
Medicines medicines = GenericDAO.get(medicinesId);
ModelAndView model = new ModelAndView("editform");
model.addObject("medicines", medicines);
return model;
}
}
Otherwise, you need to alter the link of the anchor to reference the root of the application, followed by your endpoint of /editMedicines. This can be accomplished by using the following anchor, as described here:
Edit
Edit: Try the following
MedicinesEditController
#RequestMapping(value = "/editMedicines")
public class MedicinesEditController extends HttpServlet {
private static final long serialVersionUID = 1L;
#GetMapping
public ModelAndView editMedicines(HttpServletRequest request) {
int medicinesId = Integer.parseInt(request.getParameter("id"));
Medicines medicines = GenericDAO.get(medicinesId);
ModelAndView model = new ModelAndView("editform");
model.addObject("medicines", medicines);
return model;
}
}
editform.jsp
<form class="form-signin" method="GET" action="editMedicines">
anchor
(note: try these variations, as the link changes depending on where you are when you click it. View this stack to help determine the correct link)
Edit
Edit
Edit
I am trying to validate that an integer value has been passed to the #PathVariable annotation. I have set up the following configuration file:
#Configuration
public class SpringConfiguration {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
And then I have the following in my Controller
#RestController
#Validated
public class UserController {
#RequestMapping(value = "/users/{userID}", method = RequestMethod.GET)
public ResponseEntity<User> get(
#PathVariable #NumberFormat(style = Style.NUMBER) int id) {
///Code here
}
What annotation can I use to detect if an integer value has been passed? I have tested the #Min and #Range annotations and they work correctly.
Thanks in advance.
Managed to find a solution on how to validate the path variable
here
.Using the following:
#Pattern(regexp = "\\d{9}", message = "Bank shoud be identified by exactly 9 digits")
Is there a native way with Google Cloud Endpoints to mark fields in your model as required, so that during deserialization an error is thrown if a value is not given for that field in the request's JSON body?
For example if you have the following class, you could have some kind of annotation.
public class MyModel {
private String optionalString;
private String requiredString;
public String getOptionalString() {
return optionalString;
}
public String setOptionalString() {
return optionalString;
}
public String getRequiredString() {
return optionalString;
}
#ApiSerializationProperty(required = AnnotationBoolean.TRUE)
public String setRequiredString() {
return optionalString;
}
}
I have these classes
public class Application {
public String name;
public String ico;
public List<MenuStruct> menu =new ArrayList<MenuStruct>();
//Constructor
public Application() { }
}
public class MenuStruct {
public String id;
public String type;
public String parent;
public String name;
public String secId;
//Constructor
public MenuStruct() {}
}
If I try to deserialize a collection directly in this way:
ApplicationManager apm= new ApplicationManager();
s="[ {\"name\":\"reg_salida\" , \"ico\":\"document-open-2-32x32.ico\" }]";
apm.apps=(new Gson()).fromJson(s,apm.apps.getClass() );
for (Application ap:apm.apps){
System.out.println(ap.name); //gets error here
}
I get a java.lang.ClassCastException.
But if I try to deserialize its containig class ApplicationManager it does not fail.
s="{ \"apps\": [ {\"name\":\"reg_salida\" , \"ico\":\"document-open-2-32x32.ico\" }]}";
ApplicationManager apm=(new Gson()).fromJson(s,ApplicationManager.class);
for (Application ap:apm.apps){
System.out.println(ap.name); // now no errors here! and shows reg_salida
}
Is this a bug of gson 2.2.4? or maybe I am doing something not correct?
Eduard.
You have to provide full definition of property class. Your example should looks like that:
manager.apps = gson.fromJson(json, new TypeToken<List<Application>>() {}.getType());
Using Spring 3.2.3, I'm trying to implement a simple CRUD controller that handles REST-ful URLs. It relies on a PropertyEditor to convert a path variable to a BusinessService entity by loading it from an application service. Code is as follows:
#Controller
public class BusinessServiceController {
#Autowired
private BusinessServiceService businessSvcService;
public BusinessServiceController() {
}
#InitBinder
public void initBinder(final WebDataBinder binder) {
binder.registerCustomEditor(BusinessService.class, new BusinessServicePropertyEditor(businessSvcService));
}
#RequestMapping(value = "/ui/account/business-services/{businessSvc}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ModelAndView update(#ModelAttribute("businessSvc") #Valid final BusinessService businessSvc, final BindingResult result,
final RedirectAttributes redirectAttribs) throws UnknownBusinessServiceException {
ModelAndView mav;
if (result.hasErrors()) {
mav = new ModelAndView("/business-service/edit");
}
else {
businessSvcService.updateBusinessService(XSecurity.principal().getId(), businessSvc);
mav = new ModelAndView("redirect:/ui/account/business-services");
redirectAttribs.addFlashAttribute("message", Message.info("businessService.updated", businessSvc.getTitle()));
}
return mav;
}
}
public class BusinessServicePropertyEditor extends PropertyEditorSupport {
private final BusinessServiceService businessSvcService;
public BusinessServicePropertyEditor(final BusinessServiceService businessSvcService) {
this.businessSvcService = businessSvcService;
}
#Override
public String getAsText() {
final BusinessService svc = (BusinessService) getValue();
return Long.toString(svc.getId());
}
#Override
public void setAsText(final String text) {
final BusinessService svc = businessSvcService.getBusinessService(Long.parseLong(text));
setValue(svc);
}
}
According to SPR-7608, starting from Spring 3.2, #ModelAttribute method argument resolution checks if a path variable by the same name exists (it does here), in which case it tries to convert that path variable's value to the target parameter type through registered Converters and PropertyEditors. This is not what I'm experiencing. When I inspect what ServletModelAttributeMethodProcessor does, it clearly uses the request DataBinder's ConversionService to perform type conversion, which does not consider registered PropertyEditors, and hence BusinessServicePropertyEditor#setAsText is never called.
Is this a configuration problem or an actual bug?
Thanks for your help!
Spring's ConversionService and Converters are replacement for standard Java Beans PropertyEditors.
You need to implement Converter instead of PropertyEditor if this feature is based purely on conversion service.
To register your custom converters in WebDataBinder you might use ConfigurableWebBindingInitializer or #InitBinder method.