JSON data type not validated in spring boot - json

I have json like below
"name": {
"title": "Mr",
"firstName": "somename",
"middleName": "middleName",
"lastName": "Micheal",
"maidenName": "maidenName"
}
My POJO class is defined as like below
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data
#Validated
public class Name {
#Length(min = 0,max = 10)
private String title;
#Length(min = 0,max = 50)
private String firstName;
#Length(min = 0,max = 700)
private String middleName;
#Length(min = 0,max = 50)
private String lastName;
#Length(min = 0,max = 50)
private String maidenName;
}
Controller class
#RestController
#RequestMapping("/price/v1")
#Validated
public class MyServerController implements PriceAPI {
#PostMapping(value = "/price",
produces = {"application/json"},
consumes = {"application/json"})
public ResponseEntity<SomeResponse> getmyResponse
(#Valid
#RequestBody Name name) {
return ResponseEntity.ok(myService.getmyResponse(priceData));
}
}
Issue is when I provide integer to my json first name field it is not throwing any error. example
"name": {
"title": "Mr",
"firstName": 123,
"middleName": "middleName",
"lastName": "Micheal",
"maidenName": "maidenName"
}
I tried few options in jackson and explored few Json annotation. But those are not working as expected. Please help me on this.

You will need to include a pattern for the individual field by defining a regular expression with the #Pattern annotation. In this case, for the firstName field, the appropriate #Pattern should be defined as --
#Length(min = 0, max = 50)
#Pattern(regexp = "^[A-Za-z]+$")
private String firstName;
Include a suitable pattern for all the other fields as required.

Related

How to include null values to JSON responses in spring boot REST API

I'm in the process of developing a RESTful API. I want to get user details by calling API. But my expected response not included null values.
Expected Response
{
"id": 1,
"username": "admin",
"fullName": "Geeth Gamage",
"userRole": "ADMIN",
"empNo": null
}
Actual Response
{
"id": 1,
"username": "admin",
"fullName": "Geeth Gamage",
"userRole": "ADMIN"
}
My Spring boot rest API code is below. why not include null parameters for my response?
#GetMapping(value = "/{userCode}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> findUser(#PathVariable String userCode)
{
return ResponseEntity.status(HttpStatus.OK).body(userService.getUserByUserName(userCode));
}
#Override
#Transactional
public Object getUserByUserName(String username)
{
try {
User user = Optional.ofNullable(userRepository.findByUsername(username))
.orElseThrow(() -> new ObjectNotFoundException("User Not Found"));
return new ModelMapper().map(user, UserDTO.class);
} catch (ObjectNotFoundException ex) {
log.error("Exception : ", ex);
throw ex;
} catch (Exception ex) {
log.error("Exception : ", ex);
throw ex;
}
}
User entity class and UserDTO object class as below
User.class
#Data
#Entity
#Table(name = "user")
public class User{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#Column(name = "USERNAME", nullable = false, length = 64)
private String username;
#Column(name = "USER_ROLE", nullable = false)
private String userRole;
#Column(name = "EMP_NO")
private String empNo;
}
UserDTO.class
#Data
public class UserDTO {
private Long id;
private String username;
private String fullName;
private String userRole;
private String empNo;
}
Assuming you are using Jackson you can configure its global behaviour using setSerializationInclusion(JsonInclude.Include) on the ObjectMapper.
For your use case you can configure it as NON_EMPTY or ALWAYS. For more details please check https://fasterxml.github.io/jackson-annotations/javadoc/2.6/com/fasterxml/jackson/annotation/JsonInclude.Include.html.
You can also do this at class or attribute level using the corresponding annotation #JsonInclude.

Validate 2 Json Fields for Not Null at the same time

I have below JSON . At any point of time only one of the field "car" or "bike" can be null .Not both at the same time.How can I validate json using Jackson annotations.
All the fields in JSON are mandatory
{
"name": "John",
"age": 30,
"car": "Toyota",
"bike": "Honda"
}
My Java Pojo Objects
public class Example
{
#JsonProperty("name")
public String name;
#JsonProperty("age")
public Integer age;
#JsonProperty("car")
public String car;
#JsonProperty("bike")
public String bike;
Depending what you want, you can use #NotBlank from javax.validation.constraints.NotBlank;
public class Example
{
#NotBlank(message = "This field cannot be blank")
#JsonProperty("name")
public String name;
#JsonProperty("age")
public Integer age;
#JsonProperty("car")
public String car;
#JsonProperty("bike")
public String bike;
}
You can also try #NotNull or #NotEmpty from same package. They have some differences, see what best fit on your case.

Serialize Feign Json Response to object

I've the following Json response coming from a Feign client:
{
"maxResults": 1,
"total": 5,
"isLast": false,
"values": [
{
"id": 37,
"self": "https://your-domain.atlassian.net/rest/agile/1.0/sprint/23",
"state": "active",
"name": "sprint 1",
"goal": "sprint 1 goal"
}
]
}
The feign client:
#FeignClient(name = "jira")
public interface JiraFeignClient {
#GetMapping("/rest/agile/1.0/board/{boardId}/sprint?state=active&maxResults=1")
ActiveSprintResponse getActiveSprint(#PathVariable String boardId);
}
I'd like to define the ActiveSprintResponse class in order to have the information related to the "values" property (I'm only interested in those) of the json response but I don't understand how can I easily represent it.
I would have no problems for the properties "maxResults", "total" etc... but how can easily unpack "values"? I can assume I will always have only one element in the value array.
I've tried defining it like that but it clearly does not work:
public class ActiveSprintResponse {
private final String id;
private final String self;
private final String name;
private final String goal;
public ActiveSprintResponse(String id, String self, String name, String goal) {
this.id = id;
this.self = self;
this.name = name;
this.goal = goal;
}
}
You need to define a class that represents the root JSON object. You can define a property for the values of type List then:
public class ActiveSprintResponseList {
private List<ActiveSprintResponse> values;
// (Other fields omitted for simplicity)
public void setValues(List<ActiveSprintResponse> values) {
this.values = values;
}
public List<ActiveSprintResponse> getValues() {
return values;
}
}
you then need to declare that class as return type:
#FeignClient(name = "jira")
public interface JiraFeignClient {
#GetMapping("/rest/agile/1.0/board/{boardId}/sprint?state=active&maxResults=1")
ActiveSprintResponseList getActiveSprint(#PathVariable String boardId);
}
and use it on the calling side:
ActiveSprintResponseList response = client.getActiveSprint(..);
List<ActiveSprintResponse> values = response.getValues();
// work with values

Jackson JsonMappingException: Infinite recursion (StackOverflowError)

I have a problem converting the object into its equivalent JSON.
Following is my class structure:
public class Record {
private byte[] header;
private String mti;
private String bitmap;
private int fieldNumber;
private String data;
private String name;
private String recordType;
private List<Record> subRecords;
private Field recordSchema;
private List<PDSRecord> pdsRecords;
}
In my case, a record can have multiple sub-records and then each sub-record can further have multiple sub-records. Therefore, I came up with this schema to store the records.
The problem I'm facing is due to the Circular Reference of List<Record> inside Record class.
Is there anyway Jackson could convert this object? Also, I would need the complete information of all the sub-records.
Thanks in advance
I was able to solve it. For this, I had to generate a unique Id for every object that is created and mark the class with:
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
So, the complete class looks like this:
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
#JsonInclude(JsonInclude.Include.NON_NULL)
#Data // Lombok
public class Record {
private String id;
private byte[] header;
private String mti;
private String bitmap;
private int fieldNumber;
private String data;
private String name;
private String recordType;
#ToString.Exclude // Lombok
private List<Record> subRecords;
private Field recordSchema;
private List<PDSRecord> pdsRecords;
public Record()
{
this.id = UUID.randomUUID().toString();
}
}
Hope it helps.
You can try the below code. I hope this solves your problem.
try{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
String value = mapper.writeValueAsString(r3);
System.out.println(value);
}catch(IOException a){
a.printStackTrace();
}
Output:{
"header": "UEFOS0FK",
"mti": "Data",
"bitmap": "Name",
"fieldNumber": 5,
"data": "data",
"name": "name",
"recordType": "Data",
"subRecords": [
{
"header": "UEFOS0FK",
"mti": "Data",
"bitmap": "Name",
"fieldNumber": 5,
"data": "data",
"name": "name",
"recordType": "Data",
"subRecords": [
{
"header": "UEFOS0FK",
"mti": "Data",
"bitmap": "Name",
"fieldNumber": 5,
"data": "data",
"name": "name",
"recordType": "Data",
"subRecords": null,
"recordSchema": "Record schema",
"pdsRecords": []
}
],
"recordSchema": "Record schema",
"pdsRecords": []
}
],
"recordSchema": "Record schema",
"pdsRecords": []
}

JsonArray and Gson

The JSON library I'm using is Gson. I'm having difficulty formulating a functioning data type to represent the following JSON string:
{
"latestoffers": [
{
"id": "4qXleunwNMCKi8M0q0CuMa",
"price": "534.99",
"firstrecorded_at": 1377808800,
"lastrecorded_at": 1382862800,
"seller": "Newegg",
"availability": "In stock. [BBX: Buy Box]",
"currency": "USD"
},
{
"id": "4xTIQAPySG68IS0CGyOuyO",
"price": "582.41",
"firstrecorded_at": 1380725000,
"lastrecorded_at": 1382862800,
"seller": "Beach Audio",
"currency": "USD"
},
{
"id": "5nW67R2V4CwmE8cwaWsawe",
"price": "578.04",
"firstrecorded_at": 1379524200,
"lastrecorded_at": 1379998900,
"seller": "Beach Audio",
"currency": "USD"
}
],
"offers_count": 6,
"name": "newegg.com",
"recentoffers_count": 2,
"sku": "N82E16834216463",
"url": "http://www.newegg.com/Product/Product.aspx?Item=N82E16834216463"
}
My data class (so far) is as follows, it's the method getOfferData() that I don't how to complete. I'm also not certain whether JsonArray is the appropriate JSON element to be using?
static class LatestOffers {
Integer offers_count;
String name;
Integer recentoffers_count;
String sku;
String url;
java.util.List<JsonArray> getOfferData() {
List<JsonArray> list = new ArrayList<JsonArray>();
// how do I get parse the 'id', 'price', 'firstrecorded_at' etc. to add them to the ArrayList?
return list;
}
Integer getOffers_count() {
return offers_count;
}
String getName() {
return name;
}
Integer getRecentoffers_count() {
return recentoffers_count;
}
String getSku() {
return sku;
}
String getUrl() {
return url;
}
}
Any assistance, please? Thank you.
EDIT
Turns out I was unnecessarily complicating things, this works as intended:
static class LatestOffers {
List<Offer> latestoffers;
List<Offer> getOffer() {
return latestoffers;
}
}
static class Offer {
private String id;
private String price;
private long firstrecorded_at;
private long lastrecorded_at;
private String seller;
private String availability;
private String currency;
String getId() {
return id;
}
String getPrice() {
return price;
}
long getFirstrecorded_at() {
return firstrecorded_at;
}
long getLastrecorded_at() {
return lastrecorded_at;
}
String getSeller() {
return seller;
}
String getAvailability() {
return availability;
}
String getCurrency() {
return currency;
}
}
Thank you to all who answered, I'm accepting the answer of user2762451 as (s)he was the first to suggest the use of another class for the Offer data.
I'd advise you to make new POJO for object in array.
class Offer {
private String id;
private String price;
private long firstRecordedAt;
private long lastRecordedAt;
private String seller;
private String availability;
private String currency;
}
And your LatestOffers class can have a List<Offer> offers; and the method getOfferData() should return List<Offer>.
Basically, the following:
static class LatestOfferDetail {
private int offersCount;
private String name;
private int recentOffersCount;
private String sku;
private String url;
private List<Offer> latestOffers = new ArrayList<Offer>();
//other getters and setters
public List<Offer> getLatestOffers() {
return latestOffers;
}
}
Also, you seem to be following multiple naming conventions in the same piece of code and JSON. With JAVA, it's advisable to follow CamelCaseNaming. I've updated answer to reflect those.
Also, your getter method for latestOffers has a name different from convention. It's advisable to name it like get{FieldName}. I've updated answer to reflect that.
Create another POJO contain all parameter use in array like below :
public class MyOffer
{
private String id;
private double price;
private long firstrecorded_at;
private long lastrecorded_at;
private String seller;
private String availability;
private String currency;
//your getter and setter methods here.
}
Include List of above pojo in your class LatestOffers :
List<MyOffer> latestoffers = new ArrayList<MyOffer>();
your class LatestOffers look like this
static class LatestOffers
{
Integer offers_count;
String name;
Integer recentoffers_count;
String sku;
String url;
List<MyOffer> latestoffers = new ArrayList<MyOffer>();
//getter and setter method
}
Main Class for Test:
public static void main(String[] args) {
LatestOffers lso = new LatestOffers();
lso.setName("N82E16834216463");
lso.setOffers_count(6);
lso.setRecentoffers_count(2);
lso.setSku("N82E16834216463");
lso.setUrl("http://www.newegg.com/Product/Product.aspx?Item=N82E16834216463");
MyOffer offer = null;
List<MyOffer> list = new ArrayList<MyOffer>();
for(int i=0;i<2;i++){
offer = new MyOffer();
offer.setAvailability("In stock. [BBX: Buy Box]");
offer.setCurrency("USD");
offer.setFirstrecorded_at(1377808800);
offer.setId("4qXleunwNMCKi8M0q0CuMa");
offer.setLastrecorded_at(1382862800);
offer.setPrice(534.99);
offer.setSeller("Newegg");
list.add(offer);
}
lso.setLatestoffers(list);
Gson gson = new Gson();
String json = gson.toJson(lso);
System.out.println(json);
}
Output :
{
"offers_count": 6,
"name": "N82E16834216463",
"recentoffers_count": 2,
"sku": "N82E16834216463",
"url": "http://www.newegg.com/Product/Product.aspx?Item=N82E16834216463",
"latestoffers": [
{
"id": "4qXleunwNMCKi8M0q0CuMa",
"price": 534.99,
"firstrecorded_at": 1377808800,
"lastrecorded_at": 1382862800,
"seller": "Newegg",
"availability": "In stock. [BBX: Buy Box]",
"currency": "USD"
},
{
"id": "4qXleunwNMCKi8M0q0CuMa",
"price": 534.99,
"firstrecorded_at": 1377808800,
"lastrecorded_at": 1382862800,
"seller": "Newegg",
"availability": "In stock. [BBX: Buy Box]",
"currency": "USD"
}
]
}
no need to define getOfferData() method just create list of MyOffer class and set that list into latestoffers list define in your class LatestOffers. It will serialize your list into JsonArray when you convert your POJO into JSON String.