Micronaut nested Json input Validation - java

How do you validate Json Body
{
"name": "good student",
"marks": {
"math": "122",
"english": "12"
}
}
This Doesn't works, It accepts with or without marks in JSON body, even if #NotNull etc are added to marks in Student DTO
#Introspected
public #Data class Student {
#NotBlank
private String name;
#Valid
#JsonProperty("marks")
private Marks marks;
#Introspected
static #Data class Marks{
#NotBlank
private String math;
#NotBlank
private String english;
}
}
Controller Annotated with #Validated
Method param annotated with #Valid #Body

This works for me in Micronaut version 2.0.3:
#Introspected
public #Data class Student {
#NotBlank
private String name;
#Valid
#NotNull
private Marks marks;
#Introspected
static #Data class Marks{
#NotBlank
private String math;
#NotBlank
private String english;
}
}
Field marks should be annotated by:
#NotNull - to tell the validator that it must be present
#Valid - to tell the validator that it must validate nested fields
Example controller looks like this:
#Validated
#Controller("/students")
public class StudentController {
#Post
public void create(#Valid #Body Student student) {
// do something
}
}
Tested by curl:
curl -v -X POST http://localhost:8080/students -H 'Content-Type: application/json' -d '{"name":"John"}' | jq
With this response:
{
"message": "student.marks: must not be null",
"_links": {
"self": {
"href": "/students",
"templated": false
}
}
}

Related

spring request parameter is nested json validation fail

enter image description hereI have a request like this:
#Controller
public class Test {
#ResponseBody
#PostMapping("/s")
public ResData test(#RequestBody #Valid ResData resData){
System.out.println(resData);
return resData;
}
}
#Data
class ResData{
#NotNull
#Valid
Message MSG;
int code;
}
#Data
class Message {
#NotBlank(message = "s1 cannot be blank.")
String s1;
String s2;
}
but when I test it with post some data like this:
{
"MSG":{
"s1":" ",
"s2":"ss2"
},
"code":"200"
}
it just cannot recognize:
{
"code": 10004,
"msg": "参数校验失败",
"exceptionMsg": "校验失败:MSG:must not be null, ",
"body": null
}
However, when I change the "MSG" to lowercase "msg", it just worked.
But my situation need the paramter come here is in Uppercase,
could someone tell me the truth?
thank you very much!!
I would recommend lowercase of property naming, but you can use #JsonProperty annonation to tell Jackson actual Json property is uppercase
#Data
class ResData{
#NotNull
#Valid
#JsonProperty("MSG")
Message msg;
int code;
}

How to map single entity with two different node in #ResponseBody in springboot

I am using springboot app and I want to return json in the response obtained from converting User object into json. I want to avoid creating two separate address class (billing and shipping) having specialized annotation on it. What should be the easy way for deserialization so that I could achieve my desire result.
Controller.java :
#RestController
public class Controller {
#GetMapping("/user")
public #ResponseBody User user() {
User response = new User();
response.setBillingAddress(new Address("line1", "newyork", "usa", "213321"));
response.setShippingAddress(new Address("line2", "toronto", "canada", "342222"));
return response;
}
}
User.java :
public class User {
private Address billingAddress;
private Address shippingAddress;
}
Address.java :
public class Address {
private String addressLne1;
private String city;
private String country;
private String postalCode;
}
Expected Json Response:
{
"data": {
"billing_information": {
"billing_address_line1": "line1",
"billing_city": "newyork",
"billing_country": "usa",
"billing_postal_code": "213321",
},
"shipping_information": {
"shipping_address_line1": "line2",
"shipping_city": "toronto",
"shipping_country": "canada",
"shipping_postal_code": "342222"
}
}
}

De-serialize a POJO using Lombok to send large JSON payload

I'm a QA writing some tests using Rest Assured DSL.
This is my first attempt at using Lombok to deserialize a POJO for use in the JSON Payload.
This way of building my data object, Customer, seems very cumbersome. As the test is failing with a 400, I assume I am not serializing it correctly and I'm unclear how to view the payload as JSON.
I'm not using an explicit mapping, so assume Rest Assured is using GSON by default.
Given my POJO:
import lombok.Data;
#Data
public class Customer {
private String employeeCode;
private String customer;
private String firstName;
private String lastName;
private String title;
private String dob;
private String employeeId;
}
...And example payload I need to send:
{
"employeeCode": "18ae56",
"customer": {
"firstName": "John",
"lastName": "Smith",
"title": "Mr",
"dob": "1982-01-08",
"employeeId": "2898373"
}
}
My example test is:
#BeforeClass
public static void createRequestSpecification(){
requestSpec = new RequestSpecBuilder()
.setBaseUri("https://employee-applications.company.com")
.setContentType(ContentType.JSON)
.build();
}
#Test
public void createApplicationForNewCustomer(){
Customer customer = Customer.builder().build();
customer.setEmployeeCode("18ae56");
customer.setFirstName("John");
customer.setLastName("Smith");
customer.setTitle("Mr");
customer.setDob("1982-01-08");
customer.setEmployeeId("2898373");
given().
spec(requestSpec).
and().
body(customer).
when().
post("/api/v6/applications").
then().
assertThat().statusCode(201);
}
Your POJO is incorrect and obviously the serialized JSON is not of the expected format
You should have two classes
Below is how your POJO should look like to generate the given JSON structure
#Data
public static class Customer {
#JsonProperty("firstName")
private String firstName;
#JsonProperty("lastName")
private String lastName;
#JsonProperty("title")
private String title;
#JsonProperty("dob")
private String dob;
#JsonProperty("employeeId")
private String employeeId;
}
#Data
public static class Example {
#JsonProperty("employeeCode")
public String employeeCode;
#JsonProperty("customer")
public Customer customer;
}
and your test method
Example e = new Example();
e.setEmployeeCode("18ae56");
Customer c = new Customer();
c.setFirstName("John");
c.setLastName("Smith");
c.setTitle("Mr");
c.setDob("1982-01-08");
c.setEmployeeId("2898373");
e.setCustomer(c);
given().spec(requestSpec).and().body(e).when().post("/api/v6/applications").then().assertThat()
Easiest ways to test :
String abc = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(e);
System.out.println(abc);
or
System.out.println(new Gson().toJson(e));

Send nested object to Spring POST

I have this JSON String send by Angular:
{
"transaction_id": "1234",
"usage": "Test Usage",
"billing_address": {
"first_name": "name",
"last_name": "name",
"address1": "street 1234",
"zip_code": "11923"
},
"shipping_address": {
"first_name": "name",
"last_name": "name",
"address1": "street 1234",
"zip_code": "11923"
}
}
Java code:
public class DTO {
private String transaction_id;
private String usage;
private BillingAddress billingAddress;
private ShippingAddress shippingAddress;
... getter/setter
}
public class BillingAddress {
private String firstName;
private String lastName;
private String address1;
private String zip_code;
... getter/setter
}
public class ShippingAddress {
private String firstName;
private String lastName;
private String address1;
private String zip_code;
... getter/setter
}
Spring endpoint:
#PostMapping(value = "/{id}", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> handleWpfMessage(#PathVariable("id") id,
#RequestBody DTO data){
....
}
What is the proper way to map the inner objects for billing_address and shipping_address in order values to be mapped properly? Do I need to add annotations in order to map them properly?
You should add the following annotations to your DTO class:
public class DTO {
private String transaction_id;
private String usage;
#JsonProperty("billing_address")
private BillingAddress billingAddress;
#JsonProperty("shipping_address")
private ShippingAddress shippingAddress;
... getter/setter
}
Your angular client uses snake case. In order to make jackson deserializing properly you can configure it globally with :
spring.jackson.property-naming-strategy=SNAKE_CASE
However you can also configure it for a specific class :
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class DTO {
}
As already mentioned, you can use the Jackson property mapping annotaion in your DTO class.
#JsonProperty("billing_address")
private BillingAddress billingAddress;
This means, in the json, attribute billing_address will be assigned to billingAddress variable.

Spring JPA - How JSON should be formatted and how to call with RestTemplate

I've created a service with this specification:
#RequestMapping(value = "initCustomer", method = RequestMethod.POST)
public ResponseEntity<Long> create(#RequestBody CustomerForm customerForm) {
The element CustomerForm have this structure (i omit every getter/setter method):
#XmlRootElement(name = "customer")
public static class CustomerForm {
private String name;
private String hostname;
private List<ProbeMonitor> monitors;
#XmlElement(name = "monitor")
public List<ProbeMonitor> getMonitors() {
return monitors;
}
}
The class ProbeMonitor is an #Entity with an #EmbeddedId (because this classe have more than one field in the primary key).
public class ProbeMonitor implements Serializable {
private static final long serialVersionUID = 1L;
private ProbeMonitorId id;
private Integer active;
private Date inserted;
private Date updated;
#EmbeddedId
public ProbeMonitorId getId() {
return id;
}
}
And finally, ProbeMonitorId:
#Embeddable
public class ProbeMonitorId implements Serializable {
private static final long serialVersionUID = 1L;
private String customer;
private String name;
private String type;
}
Now i should make a request to this service (using RestTemplate), but first i'm trying to use a simple REST client where i send JSON (to check that all works).
I'm sending JSON in this format, but i get "Unrecognized field "id""
{
"name": "test_name",
"hostname": "test_hosT",
"monitors": [
{ "id": {"customer": "custom"},
"active": "1"
}
]
}
I've tried to remove the "id" fields in JSON request and WebService will be invoked correctly.
How "monitors" should be formatted?
And... (this is the second question) how i should create the RestTemplate to call this?
I think to have found the problems:
1 - private ProbeMonitorId id; was not declared in JSON scope:
#EmbeddedId
**#XmlElement**
#**JsonProperty**
public ProbeMonitorId getId() {
return id;
}
2 - Inserted and updated was not declared to be ignored
#Basic
#Column(name = "Dt_Insert")
#JsonIgnore
public Date getInserted() {
return inserted;
}
3 - Correct JSON sent:
{
"name": "test_name",
"hostname": "test_hosT",
"monitors": [{
"id": {"customer": "cst", "name": "aname", "type": "atype"},
"active": "1"
}
]

Categories