Java generics and jackson mapper - java

Hi I have the following classes:
public class MyRequest {
}
and
public class MyResponse {
}
and
public class Request<T> {
private String code;
private T request;
public setCode(String code) {
this.code = codel
}
public setRequest(T request) {
this.request = request
}
}
and following service request method:
public MyResponse getMyResponse(Request<MyRequest> myRequest) {
//process
try {
ObjectMapper mapper = new ObjectMapper();
String jsonInString = mapper.writeValueAsString(myRequest);
System.out.println(jsonInString);
} catch(Exception exp) {}
}
and following Json request is sending from JavaScript;
{
"code":"TESTCODE",
"request":null
}
After I send the request I an getting an Invalid Json error. Can anyone tell me what is wrong with my request Json or something else is wrong..?

By any chance are you using the model 'Request' as an inner class. If yes,
just try using the modifier static with 'Request'.
or rather move out the model 'Request' to a separate class
Non-static Inner classes by design contain a reference to the outer-class, which does cause problems in deserialization.
http://www.cowtowncoder.com/blog/archives/2010/08/entry_411.html

Related

I am trying to create an API using SpringBoot but I don't know how to handle json request/response

I am new to Java and Spring boot. I am creating a new API.
Using postman I am sending a request body which contains request header and request payload.
Then I have a controller which handles the request with the help of RequestPayload class. (And a service and dao file but I am sure those are ok.)
Kindly let me know what Am I missing here or what do I not know.
public class RequestPayload {
String pol_pkg_prod_code;
JSONObject checklist;
public JSONObject getCheckList() {
return checklist;
}
public void setCheckList(JSONObject checklist) {
this.checklist = checklist;
}
public String pol_pkg_prod_code() {
return pol_pkg_prod_code;
}
public void setpol_pkg_prod_code(String pol_pkg_prod_code) {
this.pol_pkg_prod_code = pol_pkg_prod_code;
}
You need a POJO class that will match the structure of your JSON payload, actually a few nested classes. Spring will automatically parse JSON into this POJO.
public class Request {
private RequestPayload reqPayload;
// Getter Setter
}
public class RequestPayload {
private Checklist checklist;
// Getter Setter
}
public class Checklist {
#JsonProperty("pol_pkg_prod_code")
private String polPkgProdCode;
}
Then add it to Controller as an argument like this:
#RequestBody Request request
This tutorial explains it well
https://www.baeldung.com/spring-request-response-body

Apex Data Transfer Object. Deserializing data

I am new to Apex and SF and I have to manage some errors from an 3rd party API we are calling. I have been using DTO with very simple response objects and the error response object we get back has one more level.
JSON response from API:
{
"error": {
"message": "File couldn't be downloaded: main_panel"
}
}
DTO file:
public class CreateCadRequestError {
public string error;
public CreateCadRequestErrorMessage message;
}
public class CreateCadRequestErrorMessage {
public string message;
}
Apex class deserializing data
class SoloConnector {
resp = makeNetworkCall()...
SoloDTO.CreateCadRequestError resp = ( SoloDTO.CreateCadRequestError )JSON.deserialize( response.getBody(), SoloDTO.CreateCadRequestError.class );
System.debug('resp: ' + resp.error + resp.message);
}
I am getting an error
illegal value for primitive
I assume its my DTO class and not being able to serialize the data. Any suggetsions?
Found the answer, My DTO set up was incorrect:
public class CreateCadRequestError {
public CreateCadRequestErrorMessage error;
}
public class CreateCadRequestErrorMessage {
public string message;
}

How to handle a response of a service returning either a single object or an array of these?

I am trying to invoke a third-party API through REST call in Spring. Currently, I'm using postForObject. I am converting the request class to string and calling the post for object. The response is taken as string and then converted it into the class. I have defined the class with below parameters
Class responseDto {
private Arraylist < Response > response;
getResponse();
setResponse();
}
Response {
String code;
String trid;
Getters();
Setters();
}
I am using Jackson dependency to serialize and deserialize. This class is working fine for the below response:
{
"response":[
{
"code":"100",
"trid":"123"
}
]
}
However, in error scenario, the request returns a JSON class with the same name 'response' as given below
{
"response":{
"code":"700",
"trid":"123"
}
}
The deserialize fails for the class I defined with some JSON mapping exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not
deserialize instance of java.util.ArrayList out of START_OBJECT token
How can I resolve this issue in Java and Spring?
SOLUTION 1: Using #JsonFormat ( > 2.6 version)
Just annotate your field with #JsonFormat as
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Feature;
public class ResponseDto {
#JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List<Response> response;
public List<Response> getResponse() {
return response;
}
public void setResponse(List<Response> response) {
this.response = response;
}
}
SOLUTION 2: Setting DeserializationFeature
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
// global setting, can be overridden using #JsonFormat in beans
// when using #JsonFormat on fields, then this is not needed
mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
ResponseDto dto = mapper.readValue(stringResponse, ResponseDto.class);
}
Now response node in json containing single object, single object array, multiple object array will be successfully parsed as list of Response object.

Jaxb annotation #xmlelement(name="ElementName") not binding with xml element name

My Spring MVC Web Service code is as follows.
Model Class
#XmlRootElement(name="wrappedSecretData")
public class VendorData {
private long lKeyId;
#XmlElement(name="keyId")
public long getlKeyId() {
return lKeyId;
}
public void setlKeyId(long lKeyId) {
this.lKeyId = lKeyId;
}
}
Controller Method
#RequestMapping(value = "/vendor", method = RequestMethod.POST)
public String addVendor(#RequestBody VendorData vendorData) {
/*Checking recieved value*/
System.out.println(vendorData.getlKeyId());//**Returning 0 value **
return "Success";
}
Xml request body for web service
<wrappedVendorSecretsMetadata>
<keyId>1</keyId>
</wrappedVendorSecretsMetadata>
I am getting "0" value in lKeyId(Bold comment).
Where am I doing wrong.
Please provide the correct way to bind the xml element to object member using #XmlElement(name="keyId") annotation.
I think you need the #XmlElement only over the variable declaration.
try this:
#XmlRootElement(name="wrappedVendorSecretsMetadata")
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
public class VendorData {
private long lKeyId;
public VendorData(){
}
#XmlElement(name="keyId")
public long getlKeyId() {
return lKeyId;
}
public void setlKeyId(long lKeyId) {
this.lKeyId = lKeyId;
}
}
By default, annotations doesn't work with XmlMapper in jaxb. You have to register the annotation module for this purpose as I have done in the following code block:
String xmlData = getMyXmlData();
ObjectMapper objectMapper = new XmlMapper();
objectMapper.registerModule(new JaxbAnnotationModule());
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MyClass myObj= objectMapper.readValue(xmlData , MyClass.class);
In your case, you have to overwrite the Xml to Object binding process. To do that, you can receive the the HttpRequest in your controller and then convert the xml data to VendorData using your own java code.

Jackson: need a another method to be a setter

public class UrlTemplate extends AbstractBeanDefinition implements Serializable {
private List<HeaderField> header = new ArrayList<>();
#Tag("header")
public List<HeaderField> getHeader() {
return this.header;
}
#Node("header/header-field")
public void setHeader(HeaderField headerField) {
this.header.add(headerField);
}
public void setHeader(List<HeaderField> header) {
this.header = header;
}
}
Tag and Node annotation are used by other library, and I can't change method setHeader(HeaderField headerField).
I define a valid setter setHeader(List<HeaderField> header) for serializing, but when I try to serialize UrlTemplate to String and deserialize String to UrlTemplate, throw exception:
com.fasterxml.jackson.databind.JsonMappingException:
Conflicting setter definitions for property "header":
com.enniu.crawler.encreeper.core.domain.config.search.UrlTemplate#setHeader(1 params) vs
com.enniu.crawler.encreeper.core.domain.config.search.UrlTemplate#setHeader(1 params)
I think I may declare setHeader(List<HeaderField> header) to be the setter that Jackson take to deserialize, but I have no idea about how to do it with the Jackson.
Could any one give me some hint?
Try using JsonProperty annotation from jackson
#JsonProperty("header")
private Object headerJson;
public Object getHeaderJson() {
return status;
}
public void setHeaderJson(Object headerJson) {
this.headerJson= headerJson;
}
headerJson will be mapped to json header so it should resolve the conflict issue.

Categories

Resources