I need to validate an incoming json from a request body, some fields are required but if the json doesn't have it, they are just retrieved as null:
#Document(collection = "menus")
public class Module {
/** The module name as unique identifier. */
#Indexed(unique = true)
private String name;
/** The internationalization key. */
private String i18n;
/** The Angular state. */
private String state;
...
}
If the incoming json have this structure, without name:
{
"i18n": "INVOICES",
"state": "/invoices"
}
the Module is valid and persisted as:
{
"name": null,
"i18n": "INVOICES",
"state": "/invoices"
}
To validate this incoming json I create a Validator like this:
public class MenuValidator implements Validator {
/** The menu service. */
private MenuService service;
public MenuValidator(MenuService service) {
this.service = service;
}
#Override
public boolean supports(Class<?> objectClass) {
return objectClass.equals(Module.class);
}
#Override
public void validate(Object object, Errors errors) {
try {
String name = ((Module) object).getName());
if(name==null){
errors.rejectValue("name", "name.null","The module name is null");
}
...
}
But this is so tricky, when I have a complex structure and I need to validate all fields. Is there any options to validate my structure without validate field by field?
No i don't think there is any other alternative for such validations. You need to manually check for each property.
Thanks
Related
I'm sending a POST-Request from angular to spring. Its getting deserialized mostly correct, but one nested object is getting deserialized as an empty Object.
My Angular interfaces look as follows:
// ClientMedicalModal.ts
export interface ClientMedicalModal {
clientMedicalId: number;
client: ClientModel;
medicalEvidence: MedicalEvidence;
}
// ClientModal.ts
export interface ClientModal {
clientId: number;
}
// MedicalEvidenceModal.ts
export interface MedicalEvidenceModal {
B001: string;
B003: string;
B004: string;
}
My Java-Objects look like this:
public class ClientMedical implements Serializable {
private Integer clientMedicalId;
private Client client;
private MedicalEvidence medicalEvidence;
// getter and setter
}
public class Client implements Serializable {
private Integer clientId;
// getter and setter
}
public class MedicalEvidence implements Serializable {
private String B001;
private String B003;
private String B004;
public String getB001() {
return B001;
}
public MedicalEvidence setB001(String b001) {
B001 = b001;
}
// all other getter and setter
}
When I check the post message from my browser everything seems to be okay:
{"medicalEvidence":{"B001":"Test","B003":"TestMessage","B004":"Whatever"},"client":{"clientId":1}}
Debugging in Spring I get the request, there is a Client-Object with clientId = 1, but the ClientEvidence-Object is empty, all B00* fields are null.
See here the debugging values
Spring form binding binds the form parameters to respective fields for Client class, but MedicalEvidence is blank, so Spring instantiates a new MedicalEvidence class with all fields having null values. Why does the parameters does not get bound to the MedicalEvidence's class fields but to Client's class (and all other classes I'm using the same way)? Btw. It does not work either if I just send MedicalEvidence from Angular. The object params are still all empty.
Try using b001, b002,.. as names, the first letter should not be uppercase in your use case, except you want to use some annotation. And use 'this.' in the setter method.
public class MedicalEvidence implements Serializable {
private String b001;
private String b003;
private String b004;
^^^^
public String getB001() {
return b001;
}
public MedicalEvidence setB001(String b001) {
this.b001 = b001;
^^^^^
}
I'm creating a Spring boot REST API which should take 2 Lists of custom objects. I'm not able to correctly pass a POST body to the API I've created. Any idea what might be going wrong ?
Below is my code :
Controller Class Method :
// Main controller Class which is called from the REST API. Just the POST method for now.
#RequestMapping(value = "/question1/solution/", method = RequestMethod.POST)
public List<Plan> returnSolution(#RequestBody List<Plan> inputPlans, #RequestBody List<Feature> inputFeatures) {
logger.info("Plans received from user are : " + inputPlans.toString());
return planService.findBestPlan(inputPlans, inputFeatures);
}
Plan Class , this will contain the Feature class objects in an array:
public class Plan {
public Plan(String planName, double planCost, Feature[] features) {
this.planName = planName;
this.planCost = planCost;
this.features = features;
}
public Plan() {
}
private String planName;
private double planCost;
Feature[] features;
public String getPlanName() {
return planName;
}
// getters & setters
}
Feature POJO Class :
// Feature will contain features like - email , archive etc.
public class Feature implements Comparable<Feature> {
public Feature(String featureName) {
this.featureName = featureName;
}
public Feature() {
}
private String featureName;
// Getters / Setters
#Override
public int compareTo(Feature inputFeature) {
return this.featureName.compareTo(inputFeature.getFeatureName());
}
}
You cannot use #RequestBody twice!
You should create a class that holds the two lists and use that class with #RequestBody
You should create json like this:
{
"inputPlans":[],
"inputFeatures":[]
}
and create Class like this:
public class SolutionRequestBody {
private List<Plan> inputPlans;
private List<Feature> inputFeatures;
//setters and getters
}
POST mapping like this:
#RequestMapping(value = "/question1/solution/", method = RequestMethod.POST)
public List<Plan> returnSolution(#RequestBody SolutionRequestBody solution) {
logger.info("Plans received from user are : " + solution.getInputPlans().toString());
return planService.findBestPlan(solution);
}
I've got a simple Restful webService using Spring Boot 2.1, Java 8, running on Eclipse Neon. Im sending the following request:
<patentListWrapper>
<patentList>
<patent>
<guid>bbb</guid>
</patent>
<patent>
<guid>ccc</guid>
</patent>
</patentList>
</patentListWrapper>
and im getting back the following (incorrect) response:
<patentListWrapper>
<patentList>
<patentList>
<guid>ddd</guid>
</patentList>
<patentList>
<guid>eee</guid>
</patentList>
</patentList>
</patentListWrapper>
ie i've got 2 patentList elements in the response ,instead of an inner patent element, and I don't know why. My 2 POJO classes to map the request are:
public class PatentListWrapper {
private List<Patent> patents;
public List<Patent> getPatentList() {
return patents;
}
public void setPatentList(List<Patent> patents) {
this.patents = patents;
}
}
and:
public class Patent {
private String guid;
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public Patent() {
super();
}
}
my REST Controller class is:
#RestController
public class PndController {
#Autowired
ReadFromDb db;
#RequestMapping(value = "/guidRequest/xmlList", method = RequestMethod.POST, produces = { "application/xml", "text/xml" }, consumes = MediaType.ALL_VALUE )
public PatentListWrapper guidSearchList(#RequestBody PatentListWrapper patentListWrapper) {
System.out.println("DS in guidSearchList()");
patentListWrapper = db.readGuidsFromDb(patentListWrapper); // Set the guid in the patents List in patentListWrapper
return patentListWrapper;
}
}
and ReadFromDb class:
#Repository
public class ReadFromDb {
public PatentListWrapper readGuidsFromDb(PatentListWrapper patentListWrapper) {
List<Patent> patents= patentListWrapper.getPatentList();
for(Patent patent : patents) {
patent.setGuid("aaa");
}
patentListWrapper.setPatentList(patents);
return patentListWrapper;
}
}
I'm sending my resuest using the windows ARC Advanced Rest Client:
Rest client with Content-type=application/xml
I've established that both patentList element names map to getPatentList() in PatentListWrapper. How do I get the response envelope to match the request envelop? Any help appreciated.
it is true , just create the getter setter method with the same variable name like below instead of using different names for getter setter methods
private List<Patent> patents;
public List<Patent> getPatents() {
return patents;
}
public void setPatents(List<Patent> patents) {
this.patents = patents;
}
or use the GSON and use #JsonProperty and define the required value name , further if you are not using the IDE to generate getters and setters you better use lombok plugin .
I am building project on spring boot and want to add validation that are easy to integrate.
I have Pojo for my project as below:
public class Employee{
#JsonProperty("employeeInfo")
private EmployeeInfo employeeInfo;
}
EmployeeInfo class is as below:
public class EmployeeInfo extends Info {
#JsonProperty("empName")
private String employeeName;
}
Info class is as below:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Info {
#JsonProperty("requestId")
protected String requestId;
}
How to I validate if request Id is not blank with javax.validation
My controller class is as below:
#RequestMapping(value = "/employee/getinfo", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<> getEmployee(#RequestBody Employee employee) {
//need to validate input request here
//for e.g to check if requestId is not blank
}
Request :
{
"employeeInfo": {
"requestId": "",
}
}
Considering you are making use of validation-api:
Please try using below to validate if your String is not null or not containing any whitespace
#NotBlank
In order to validate request parameters in controller methods, you can either use builtin validators or custom one(where you can add any type of validations with custom messages.)
Details on how to use custom validations in spring controller, Check how to validate request parameters with validator like given below:
#Component
public class YourValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(Employee.class);
}
#Override
public void validate(Object target, Errors errors) {
if (target instanceof Employee) {
Employee req = (Employee) target;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "employeeInfo.requestId", "YourCustomErrorCode", "yourCustomErrorMessage");
//Or above validation can also be done as
if(req.getEmployeeInfo().getRequestId == null){
errors.rejectValue("employeeInfo.requestId", "YourCustomErrorCode", "YourCustomErrorMessage");
}
}
}
}
In a web application I'm working on using Spring 2.5.6.SEC01, I essentially have an Integer field that takes a number to determine which page to scroll to. The requirements changed, and we no longer want to display an error message, but simply ignore the user's input if they enter an invalid number, say "adfadf".
I was reading that you can do that via:
TypeMismatch.property=Some New Error Message
However, after having tried that, we are still getting the original error message:
java.lang.Integer.TypeMismatch=...
I only want to disable this message for that given property. How can I do that? I still want binding to occur automatically, I just don't want to hear about it now.
Walter
According to DefaultMessageCodesResolver
In case of code "typeMismatch", object name "user", field "age"
typeMismatch.user.age
typeMismatch.age
typeMismatch.int
typeMismatch
So you should get (I suppose your commandName is called command and your property is age) Adapt according to your code
typeMismatch.command.age
typeMismatch.age
typeMismatch.java.lang.Integer
typeMismatch
Notice The third code
typeMismatch.java.lang.Integer
It will solve what you want
UPDATE
I have created a Person command class
public class Person implements Serializable {
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
And a person controller
public class PersonController extends SimpleFormController {
public PersonController() {
setCommandClass(Person.class);
setValidator(new Validator() {
public boolean supports(Class clazz) {
return clazz.isAssignableFrom(Person.class);
}
public void validate(Object command, Errors errors) {
rejectIfEmpty(errors, "age", "Age is required");
}
});
}
#Override
protected ModelAndView onSubmit(Object command) throws Exception {
return new ModelAndView();
}
}
Here goes my myMessages.properties (root of the classpath)
typeMismatch.command.age=typeMismatch.command.age
typeMismatch.age=typeMismatch.age
typeMismatch.java.lang.Integer=typeMismatch.java.lang.Integer
typeMismatch=typeMismatch
So, i have done the following test
public class PersonControllerTest {
private PersonController personController;
private MockHttpServletRequest request;
private MessageSource messageSource;
#Before
public void setUp() {
request = new MockHttpServletRequest();
request.setMethod("POST");
personController = new PersonController();
messageSource = new ResourceBundleMessageSource();
((ResourceBundleMessageSource) messageSource).setBasename("myMessages");
}
#Test
public void failureSubmission() throws Exception {
/**
* Ops... a bindException
*
* Age can not be a plain String, It must be a plain Integer
*/
request.addParameter("age", "not a meaningful age");
ModelAndView mav = personController.handleRequest(request, new MockHttpServletResponse());
BindingResult bindException = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + "command");
for (Object object : bindException.getAllErrors()) {
if(object instanceof FieldError) {
FieldError fieldError = (FieldError) object;
assertEquals(fieldError.getField(), "age");
/**
* outputs typeMismatch.command.age
*/
System.out.println(messageSource.getMessage((FieldError) object, null));
}
}
}
}
If you want the second one, you must get rid of typeMismatch.command.age key resource bundle
typeMismatch.age=typeMismatch.age
typeMismatch.java.lang.Integer=typeMismatch.java.lang.Integer
typeMismatch=typeMismatch
Or write your own implementation of MessageCodesResolver
public class MyCustomMessageCodesResolver implements MessageCodesResolver {
private DefaultMessageCodesResolver defaultMessageCodesResolver = new DefaultMessageCodesResolver();
public String [] resolveMessageCodes(String errorCode, String objectName) {
if(errorCode.equals("age"))
/**
* Set up your custom message right here
*/
return new String[] {"typeMismatch.age"};
return defaultMessageCodesResolver.resolveMessageCodes(String errorCode, String objectName);
}
public void String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) {
if(errorCode.equals("age"))
/**
* Set up your custom message right here
*/
return new String[] {"typeMismatch.age"};
return defaultMessageCodesResolver.resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType);
}
}
And set up your PersonController
public class PersonController extends SimpleFormController {
public PersonController() {
setMessageCodesResolver(new MyCustomMessageCodesResolver());
setCommandClass(Person.class);
setValidator(new Validator() {
public boolean supports(Class clazz) {
return clazz.isAssignableFrom(Person.class);
}
public void validate(Object command, Errors errors) {
rejectIfEmpty(errors, "age", "Age is required");
}
});
}
You can register a custom PropertyEditor for that field, which wouldn't fail on type mismatch.
Since this is a Spring MVC application and assuming that it is a simple form, you can set this up in many ways. Can you specify your controller settings? For post request, you can record a suppressed field before the validator is called (assuming you have specified one) or after the validator is called. If you want to do it before validation, you can call [this][2]. After validation, you can call [this][3]
[2]: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html#onBind(javax.servlet.http.HttpServletRequest, java.lang.Object, org.springframework.validation.BindException)
[3]: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/mvc/BaseCommandController.html#onBindAndValidate(javax.servlet.http.HttpServletRequest, java.lang.Object, org.springframework.validation.BindException)