Unable to parse json with List elements inside it - java

I have a Java class which has 2 List Object inside it and i am Json serializing the parent class.
#JsonSerialize
public class RequestSalesJson {
#JsonProperty("nonUniqueSalesList")
private List<SalesDataJson> getNonUniqueSalesDataJson;
#JsonProperty("uniqueSalesList")
private List<SalesDataJson> uniqueSalesDataJson;
public List<SalesDataJson> getGetNonUniqueSalesDataJson() {
return getNonUniqueSalesDataJson;
}
public void setGetNonUniqueSalesDataJson(List<SalesDataJson> getNonUniqueSalesDataJson) {
this.getNonUniqueSalesDataJson = getNonUniqueSalesDataJson;
}
public List<SalesDataJson> getUniqueSalesDataJson() {
return uniqueSalesDataJson;
}
public void setUniqueSalesDataJson(List<SalesDataJson> uniqueSalesDataJson) {
this.uniqueSalesDataJson = uniqueSalesDataJson;
}
}
SalesReturnJson.java
#JsonSerialize
public class SalesReturnJson {
#JsonProperty("starttime")
private String startTime;
#JsonProperty("pn")
private String partNumber;
#JsonProperty("so")
private String SalesOrderNumber;
#JsonProperty("wo")
private String workOrderNumber;
#JsonProperty("loc")
//other variables declared..
}
Controller.java :-
#RequestMapping(value = "/addAllSalesData",method = RequestMethod.POST)
public void addAllSalesData(#RequestBody RequestSalesJson requestSalesJsons){
log.info("POST : '/addSalesData'");
try{
System.out.print("In Controller "+requestSalesJsons.getUniqueSalesDataJson());
//salesService.processSalesData(requestSalesJsons);
}
catch(Exception e){
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
}
The value here is coming to be null.
Below is the json i am using :-
{ "uniqueSalesJson": [{"SO":4000955,"Part Number":"000","Locator":255638,"Lot Number":"P01-2059139","Reservation Quantity":2,"Status":"Released to warehouse","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"},{"SO":4000955,"Part Number":"000","Locator":255652,"Lot Number":"P01-2059140","Reservation Quantity":10,"Status":"Released to warehouse","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"}],"nonUniqueSalesJson":[{"SO":4000992,"Part Number":"1276M84G15","Locator":12345,"Lot Number":"P01-2344141","Reservation Quantity":6,"Status":"PACKED","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"},{"SO":4000992,"Part Number":"1276M84G15","Locator":12345,"Lot Number":"P01-2344141","Reservation Quantity":6,"Status":"PICKED","COE":"Fabrication","ORG":"P07","Start_Time":"2017-09-19 11:21:36"}]}

There are some issues in your code that let me doubt that your application compiles. First of all, rename the SalesReturnJson class to SalesDataJson.
Then check your #JsonProperty annotations. The value here must match exactly the property key in the Json String. Refactoring all this stuff will lead you to your root entity class:
#JsonSerialize
public class RequestSalesJson {
#JsonProperty("nonUniqueSalesJson")
private List<SalesDataJson> nonUniqueSalesDataJson;
#JsonProperty("uniqueSalesJson")
private List<SalesDataJson> uniqueSalesDataJson;
...
}
and your SalesDataJson class (missing a lot of attributes which the mapper ignores by configuration):
#JsonSerialize
public class SalesDataJson {
#JsonProperty("Start_Time")
private String startTime;
#JsonProperty("Part Number")
private String partNumber;
#JsonProperty("SO")
private String SalesOrderNumber;
}
This sample works as expected with the com.fasterxml.jackson.databind.ObjectMapper
Hope that helps!

Related

Using #JsonCreator to create two instances of same class in one JSON DTO

I would like to deserialize JSON of this structure:
{
"employee_pricing_type":"COMPUTE_BY_OWN_RATE",
"employee_rate":10,
"customer_pricing_type":"COMPUTE_BY_OWN_RATE",
"customer_rate":200
}
I have such POJO to create price setting from a HTTP request:
public class ObjectPricingSetting {
#JsonProperty("pricing_type") // describes output
private final ObjectPricingType pricingType;
#JsonProperty("own_rate") // describes output
private final BigDecimal ownRate;
public ObjectPricingSetting(final ObjectPricingType pricingType, final BigDecimal ownRate) {
AssertUtils.notNull(pricingType, "pricingType");
this.pricingType = pricingType;
if (ownRate != null) {
AssertUtils.isGtZero(ownRate, "ownRate");
this.ownRate = ownRate;
} else {
this.ownRate = null;
}
}
public ObjectPricingType getPricingType() {
return pricingType;
}
public BigDecimal getOwnRate() {
return ownRate;
}
}
this is DTO:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonProperty(value = "employee_pricing_setting")
private ObjectPricingSetting employeePricingSetting;
#JsonProperty(value = "customer_pricing_setting")
private ObjectPricingSetting customerPricingSetting;
}
I would like to create these two instances of ObjectPricingSetting with #JsonCreator.
Q: How should I anotate #JsonProperty parameter in ObjectPricingSetting constructor to recognize what JSON value should use to create these two instances?
You can use #JsonUnwrapped with a prefix in your parent class:
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectPricingCommand extends BaseDto<ObjectId> {
#JsonUnwrapped(prefix = "employee_")
private ObjectPricingSetting employeePricingSetting;
#JsonUnwrapped(prefix = "customer_")
private ObjectPricingSetting customerPricingSetting;
}
Then you can use the normal #JsonCreator/#JsonProperty in your nested DTO, without the prefix:
public class ObjectPricingSetting {
#JsonCreator
public ObjectPricingSetting(
#JsonProperty("pricing_type") final ObjectPricingType pricingType,
#JsonProperty("rate") final BigDecimal ownRate) {
...

#RestController autoserialize POJO's

I have a Spring mvc application, with a #RestController like such:
#RestController
#RequestMapping("levels")
public class LevelController {
private final GetLevelOneCount getLevelOneCount;
private final GetLevelTwoCount getLevelTwoCount;
private final GetLevelThreeCount getLevelThreeCount;
#Inject
public LevelController(GetLevelOneCount getLevelOneCount,
GetLevelTwoCount getLevelTwoCount,
GetLevelThreeCount getLevelThreeCount) {
this.getLevelOneCount = getLevelOneCount;
this.getLevelTwoCount = getLevelTwoCount;
this.getLevelThreeCount = getLevelThreeCount;
}
#GetMapping("/level1/{id}")
public LevelModel levelOne(#PathVariable String id) throws SQLException {
LevelModel levelOneModel = new LevelModel();
levelOneModel.setLevelQuery(getLevelOneCount.execute(id));
levelOneModel.setLevelDirQuery(getLevelOneCount.executeDir(id));
levelOneModel.setLevelDateQuery(getLevelOneCount.executeDate(id));
return levelOneModel;
}
my LevelModel is a POJO with private variables, now i wonder, if this can get serialized to propper JSON with private variables?
package com.pwc.tag.service.levels;
public class LevelModel {
private Long LevelQuery;
private Long LevelDirQuery;
private Long LevelDateQuery;
public Long getLevelQuery() {
return LevelQuery;
}
public void setLevelQuery(Long levelQuery) {
LevelQuery = levelQuery;
}
public Long getLevelDirQuery() {
return LevelDirQuery;
}
public void setLevelDirQuery(Long levelDirQuery) {
LevelDirQuery = levelDirQuery;
}
public Long getLevelDateQuery() {
return LevelDateQuery;
}
public void setLevelDateQuery(Long levelDateQuery) {
LevelDateQuery = levelDateQuery;
}
}
Yes, your object will be serialized to a proper JSON structure including the private field, because of the getters and setters.
If these fields should not be present in the output object, you can add the #JsonIgnore annotation to exclude them from the JSON structure.
P.S. the common approach is to start names of java properties with a lower case letter.

Create a Post method to save an object with multiples id

I have in my controller:
#RestController
public class OneTwoController {
private OnTwoService _service;
//... more code
#PostMapping("/api/one-two")
#CrossOrigin
public ResponseEntity<ServiceResponse> save(#RequestBody OneTwo model) {
return ResponseEntity.ok().body( _service.Save(model));
}
In my entity:
#Entity(name = "OneTwo")
#Where (clause = "deleted='false'")
public class OneTwo{
#EmbeddedId
private OneTwoKey_id;
public OneTwo(OneTwoKey id) {
this._id = id;
}
#JsonProperty("oneTwo")
public void setId(OneTwoKey value) {
this._id = value;
}
The OneTwoKey class:
public class OneTwoKey implements Serializable {
#Column(name = "OneID")
private int _oneID;
#Column(name = "TwoID")
private int _twoID;
public OneTwoKey(int oneID, int twoID) {
this._oneID = oneID;
this._twoID = twoID;
}
}
The json that I send to the Rest API:
{
"oneTwo": {
"oneID": 83,
"twoID": 69
},
"deleted": true
}
The issue is that both ids arrive null, so the service can't do the insert on the DB.
How can I deal with those cases when the ids are more than one?
Try adding setters in the OneTwoKey class to make it easier for the JSON deserializer:
#JsonProperty("oneID")
public void setOneID(int oneID) {
this._oneID = oneID;
}
#JsonProperty("twoID")
public void setTwoID(int twoID) {
this._twoID = twoID;
}
Another solution is to create a DTO, use it to receive the data in the controller and then convert it to your entity:
public class OneTwoDTO {
private Map<String, Int> oneTwo;
private boolean deleted;
// setters & getters
}
Simply what you can do is instead of using
public ResponseEntity<ServiceResponse> save(#RequestBody OneTwo model) {
you can use
public ResponseEntity<ServiceResponse> save(#RequestBody String model) {
Now convert the String to json and get all the key value pairs, it would be easier if you have dynamic number of variables and you want to capture them all.
or you can use tools like jsonschema2pojo whick take a json schema and generate a pojo. In the json schema if you set
"additionalProperties": true
you can capture all the values.
Could you make sure the problem is not because of case sensitivity?
Lower case the column names. Also could you use public access on those variables as well? These are my initial guesses as to why the payload is not being binded correctly.
public class OneTwoKey implements Serializable {
#Column(name = "oneID")
public int _oneID;
#Column(name = "twoID")
public int _twoID;

JAXB Unmarshall XML with same tag name but different structure

I'm trying to unmarshall this kind of XML:
<result>
<avance>0.0000</avance>
<operation_status>0</operation_status>
<service>Bank Account</service>
<service>
<min_amount>1.00</min_amount>
<max_amount>1499.00</max_amount>
<currency>USD</currency>
</service>
</result>
I have created this kind of class structure:
public class Result {
private BigDecimal avance;
private Integer operationStatus;
private String serviceDesc;
private Service service;
#XmlElement(name = "service")
public String getServiceDesc() {
return serviceDesc;
}
public void setServiceDesc(String serviceDesc) {
this.serviceDesc = serviceDesc;
}
#XmlElement(name = "service")
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
#XmlElement(name = "avance")
public BigDecimal getAvance() {
return avance;
}
public void setAvance(BigDecimal avance) {
this.avance = avance;
}
#XmlElement(name = "operation_status")
public Integer getOperationStatus() {
return operationStatus;
}
public void setOperationStatus(Integer operationStatus) {
this.operationStatus = operationStatus;
}
}
and Service looks like this:
#XmlRootElement
public class Service {
private BigDecimal minAmount;
private BigDecimal maxAmount;
private String currency;
#XmlElement(name = "min_amount")
public BigDecimal getMinAmount() {
return minAmount;
}
public void setMinAmount(BigDecimal minAmount) {
this.minAmount = minAmount;
}
#XmlElement(name = "max_amount")
public BigDecimal getMaxAmount() {
return maxAmount;
}
public void setMaxAmount(BigDecimal maxAmount) {
this.maxAmount = maxAmount;
}
#XmlElement(name = "currency")
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}
When I receive response from some external service I'm able to unmarshal that string and result has correct Service class set but serviceDesc is always null. Is there any way how I can unmarshall this structure correctly?
In another question (for which this question is marked as duplicate) case is when you have same tag name but different number of attributes in my case content of the tag is different, also in that question classes to which content should be unmarshaled are child and parent in my case one is String another one some custom object. Think that's why I wasn't able to implement XmlAdapter properly.
Your XML structure is not valid.
You shouldn't have the same tag twice for different structure in the same namespace.
Solutions :
Rename your tag (serviceDesc for example)
Use 2 different namespaces ( ns1:service and ns2:service for example)

Getting JsonMappingException while sending data to view

I am trying to show DB data to my webpage.
I have made following code when GET request to the #RequestMapping(value = "/api/binder").
but when get request came to this method it will fetch data (I have print on console and display well) but it doesn't map to my Java Script Ajax call, it's showing me an error.
Following is my code for to fetch data :
#Autowired
IBinderViewRepository repository;
#RequestMapping(method= RequestMethod.GET)
public #ResponseBody
List<BinderResponse> getBinders(){
List<BinderView> binders = repository.getBinders();
List<BinderResponse> responses = new ArrayList<>();
ModelMapper mapper = Mapper.getInstance();
for(int i = 0; i < binders.size(); i++){
System.out.println("In Loop");
BinderResponse response = mapper.map(binders.get(i),BinderResponse.class);
System.out.println("Data :: " + response.getBinderName());
responses.add(response);
}
return responses;
}
but it shows me following error :
HTTP Status 500 - Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"])
Here is ajax call from knockout js :
ajax.get('api/binder').done(function(response){ ... }
Here BinderView and BinderResponse have same fields :
private String binderName;
private String binderAddress1;
and getter setter as well in both.
and repository.genBinders() method bring data from DB.
Here is insert method and works fine for me :
#RequestMapping(method= RequestMethod.POST,consumes = "application/json")
public #ResponseBody
IWebApiResponse addBinder(#RequestBody AddBinderForm binder){
.....
}
Shall I have to put any json annotation on my BinderResponse class ?
I don't understand where am i wrong ?Anyone pleas guide me.
UPDATE :
public class BinderResponse extends WebApiResponseBase {
private String binderName;
private String binderAddress1;
public String getBinderName() {
return binderName;
}
public void setBinderName(String binderName) {
this.binderName = binderName;
}
public String getBinderAddress1() {
return binderAddress1;
}
public void setBinderAddress1(String binderAddress1) {
this.binderAddress1 = binderAddress1;
}
}
BinderView :
public class BinderView extends BaseView {
private String binderName;
private String binderAddress1;
public String getBinderName() {
return binderName;
}
public void setBinderName(String binderName) {
this.binderName = binderName;
}
public String getBinderAddress1() {
return binderAddress1;
}
public void setBinderAddress1(String binderAddress1) {
this.binderAddress1 = binderAddress1;
}
}
In console it prints data / BinderName :
In Loop
Data :: ada
In Loop
Data :: tya
New Update :
Here is BaseView :
#MappedSuperclass
public abstract class BaseView implements IEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
private long id;
public long getId() {
return id;
}
public void setId(long id) {
if (this.id != 0 && this.id != id) {
throw new IllegalStateException(
"The ID must not be changed after it is set.");
}
this.id = id;
}
}
and In IEntity :
public interface IEntity extends Serializable {
long getId();
void setId(long id);
}
WebApiResponseBase :
public class WebApiResponseBase implements IWebApiResponse {
private String _uri;
#Override
public String getUri() {
return _uri == null ? "" : _uri;
}
#Override
public void setUri(String uri) {
_uri = uri;
}
}
Jackson, by default, serializes an object's whole inheritance hierarchy, ie. the parent class fields as well. In the case of
public class BinderResponse extends WebApiResponseBase {
it seems like
Could not write JSON: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: java.util.ArrayList[0]->com.ngl.dto.outgoing.BinderResponse["valid"])
Jackson tries to serialize a field called valid from a getter called isValid (which is a conventional bean property name). The getter method, however, seems to throw a NullPointerException for whatever reason.
If you want Jackson to ignore it, you can annotate the getter with #JsonIgnore or your class with #JsonIgnoreProperties and specify the property name, ie. valid.
In my case when I used #JsonIgnore the exception has been gone but the problem was it couldn't receive that value from API Request anymore and Spring ignored it (obviously because of #JsonIgnore) So I investigated about the issue and figured out that the problem was the getter and setter.
I had the Integer property while my getter was int. So when I changed the getter to Integer my problem solved and error's gone.
private Integer purchaseId;
#JsonIgnore
public int getPurchaseId() {
return purchaseId;
}
public void setPurchaseId(int purchaseId) {
this.purchaseId = purchaseId;
}
Changed to :
private Integer purchaseId;
public Integer getPurchaseId() {
return purchaseId;
}
public void setPurchaseId(Integer purchaseId) {
this.purchaseId = purchaseId;
}
#Column(name="createddate")
private Date createdDate;
#Transient
private String formatedCreatedDate;
public String getFormatedCreatedDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
return dateFormat.format(this.getCreatedDate());
}
It throws the same exception because here may be null by calling getCreatedDate() value come so it can't format null date so keep null check here like:
Solution
public String getFormatedCreatedDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/mm/yyyy");
Date createDdate=this.getCreatedDate();
if(createDdate!=null){
return dateFormat.format(createDdate);
}
return "-";
}

Categories