Nested elements with List is null with ResponseEntity in Spring - spring-restcontroller

I have a REST Controller as follows using Spring boot 1.3.5 and Java 8. This works perfect while testing with Advanced REST Client (ARC) Utility - send xml request and returns the expected xml response as shown right below this controller code.
#RestController
#EnableAutoConfiguration
#RequestMapping("/rateQuote")
public class RateQuoteController {
#Autowired
private RateQuotingService rateQuotingService;
#RequestMapping(method = RequestMethod.POST, consumes = {"application/json","application/xml"}, produces = {"application/json","application/xml"})
public ResponseEntity<RateQuoteDto> getRateQuote(#RequestBody RESTRequestDto request){
RateQuoteDto rateQuoteDto = rateQuotingService.getRateQuote(request.getStateCode(), request.getZipCode(), request.getClient(), request.getThreshold(),
benefit,request.getLob(), localEffectiveDate);
return (new ResponseEntity<>(rateQuoteDto, HttpStatus.OK));
}
}
Request with ARC-
url - http://localhost:8080/rateQuote
Method - POST
Headers -
Content-Type: application/xml
Accept: application/xml
Request Body -
<request>
<stateCode>NY</stateCode>
<zipCode>10005</zipCode>
<client>BMG</client>
<threshold>1000</threshold>
<lob>PDI</lob>
<benefitLevel>15000</benefitLevel>
<effectiveDate>2016-01-01</effectiveDate>
</request
Response -
<?xml version="1.0" encoding="UTF-8"?>
<rateQuote>
<status>Approve</status>
<message>Quote is successfully retrieved.</message>
<quote>
<threshold1 amount="1000">
<benefits>
<benefitLevel amount="15000">
<annualPremium>990.00</annualPremium>
<semiAnnualPremium>440.00</semiAnnualPremium>
<quaterlyPremium>200.00</quaterlyPremium>
<monthlyPremium>77.00</monthlyPremium>
</benefitLevel>
</benefits>
</threshold1>
</quote>
</rateQuote>
So far so good. However, I have an issue with response when call is made grammatically.And the issue is that the most of the response's nodes are null as shown below:
#Test
public void getQuote()throws Exception{
RestTemplate template = new RestTemplate();
//RESTRequestDto is JAXB decorated
RESTRequestDto body = new RESTRequestDto();
body.setStateCode("NY");
body.setZipCode("10005");
body.setClient("BMG");
body.setThreshold("1000");
body.setLob("PDI");
body.setBenefitLevel("15000");
body.setEffectiveDate(DateUtils.createDate("2016-01-01", "yyyy-MM-dd"));
RequestEntity<RESTRequestDto> request = RequestEntity.post(new URI("http://localhost:8080/rateQuote"))
.accept(MediaType.APPLICATION_XML).contentType(MediaType.APPLICATION_XML).body(body);
ResponseEntity<RateQuoteDto> response = template.exchange(request, RateQuoteDto.class);
RateQuoteDto rateQuote = response.getBody();
System.out.println(rateQuote);
}
Response -
RateQuoteDto{status=Approve, message=Quote is successfully retrieved., zipCode=null, clientId=null, quote=QuoteDto{threshold1=ThresholdDto{amount=1000, benefitLevelLst=null}}}
However, changing the Media Type to JSON works as shown below:
RequestEntity<RESTRequestDto> request = RequestEntity.post(new URI("http://localhost:8080/rateQuote"))
.accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).body(body);
Response -
RateQuoteDto{status=Approve, message=Quote is successfully retrieved., zipCode=10005, clientId=BMG, quote=QuoteDto{threshold1=ThresholdDto{amount=1000, benefitLevelLst=[BenefitDto{amount=15000, annualPremium=990.00, semiAnnualPremium=440.00, quaterlyPremium=200.00, monthlyPremium=77.00}]}}}
Observation -
As shown below, the ist benefitLevelLst is not bound with MediaType.XML returning null value show above but works just fine with MediaType.JSON. Any idea as to why?
public class ThresholdDto {
#XmlAttribute
private String amount;
#XmlElementWrapper(name = "benefits")
#XmlElement(name = "benefitLevel")
private List<BenefitDto> benefitLevelLst;
. . .
}

Related

Rest API return response XML format, but same xml not get in result by using httpclient

I have created web api which return xml format response. like below
<TXLife xmlns="http://ACORD.org/Standards/Life/2">
<TXLifeResponse>
<TransRefGUID>61ec7f39-5744-410e-b601-dcd89d8d6f27</TransRefGUID>
<TransType tc="510">Form Instance Update</TransType>
<TransSubType tc="1022500310">Annuity Application for Mani ManiM</TransSubType>
<TransExeDate>2016-08-25-04:00</TransExeDate>
<TransExeTime>16:36:41.157-04:00</TransExeTime>
<TransMode tc="2">Original</TransMode>
<NoResponseOK tc="0"/>
<TransResult>
<ResultCode tc="3">Received Pending</ResultCode>
</TransResult>
But when call API using httpclient, I received response but response data is not same as above instead i got decode of special character.
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"><?
xml version="1.0" encoding="utf-8"?>
<TXLife xmlns:acord="http://ACORD.org/Standards/Life/2">
<TXLifeResponse>
<TransRefGUID>dd8973e3-ac03-4690-908b-
65da3d6a770f</TransRefGUID>
<TransType tc="510">Form Instance Update</TransType>
<TransSubType tc="1022500310">
Annuity Application for SUZANNE M PERSON</TransSubType>
<TransExeDate>2020-08-17</TransExeDate>
<TransExeTime>15:28:24Z</TransExeTime>
<TransMode tc="2">Original</TransMode>
<NoResponseOK tc="0" />
<TransResult>
<ResultCode tc="3">Received Pendinge</ResultCode>
</TransResult>
</TXLifeResponse>
</TXLife></string>
I am using below code to call API
string response = string.Empty;
using (var client = new HttpClient())
{
client.BaseAddress = parameters.DestinationUri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
var responseTask = client.PostAsXmlAsync(parameters.DestinationUri, request);
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
response = result.Content.ReadAsStringAsync().Result;
}
Resolved. I fixed by just in API response. I return HttpResponseMessage instead of return string object. Changes in API like below
string response = "response string info";
return new HttpResponseMessage()
{
Content = new StringContent(response, Encoding.UTF8, "application/xml")
};

GDAX Post Call returns invalid signature

I am trying to make a post request on GDAX.
But I always receive a "invalid signature" message.
GDAX API Docs for creating request + signing: https://docs.gdax.com/#creating-a-request
Preshash string returns the following:
1500627733POST/orders{"price":"1000.0","size":"0.02","type":"limit","side":"sell","product_id":"BTC-EUR"}
My signature method:
public String generateSignature(String requestPath, String method, String body, String timestamp) {
try {
String prehash = timestamp + method.toUpperCase() + requestPath + body;
byte[] secretDecoded = Base64.getDecoder().decode(secretKey);
SecretKeySpec keyspec = new SecretKeySpec(secretDecoded, "HmacSHA256");
Mac sha256 = (Mac) Mac.getInstance("HmacSHA256").clone();
sha256.init(keyspec);
return Base64.getEncoder().encodeToString(sha256.doFinal(prehash.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
My request method:
private boolean placeLimitOrder(String currencyPair, String side, String price, String size)
throws UnirestException {
String timestamp = Instant.now().getEpochSecond() + "";
String api_method = "/orders";
String path = base_url + api_method; //base_url = https://api.gdax.com
String method = "POST";
String b = "{\"price\":\"1000.0\",\"size\":\"0.02\",\"type\":\"limit\",\"side\":\"sell\",\"product_id\":\"BTC-EUR\"}";
JsonNode n = new JsonNode(b);
String sig = generateSignature(api_method, method,b, timestamp);
HttpResponse<JsonNode> rep = Unirest.post(path).header("accept", "application/json")
.header("content-type", "application/json")
.header("CB-ACCESS-KEY", publicKey)
.header("CB-ACCESS-PASSPHRASE", passphrase)
.header("CB-ACCESS-SIGN", sig)
.header("CB-ACCESS-TIMESTAMP", timestamp)
.body(n)
.asJson();
System.out.println(rep.getStatusText()); //Bad Request
System.out.println(rep.getBody().toString()); //invalid signature
System.out.println(sig); //returns something
return false;
}
I also tried to make a API Request Call with Insomnia but it returns the same message ("invalid signature").
Any clues?
Thank you very much in advance!
Looks like you are signing the price order data which is a string, but for the body in the post you are turning it into a json node. Which may not match when gdax decodes the signing and compares the payload data to the decrypted(signed body) when they receive it.
Why not just send the string as the body and remove the ".asJson"?
.body(b)
I was stuck on a similar issue when I was testing the API in C#. After 3 afternoons of trying. I tested sending the data as a string and I was able to get pass the invalid signature error.
I had the same problem.
I used http:
but the right one httpS:
Problem solved.

Edit worker additional data using Workday API

I'd like to edit custom employee data in Workday using their API but the actual custom data format is not specified in the documentation. Also, I was not able to find a way to retrieve additional worker data. Google doesn't find any examples of using their API for this (Edit_Worker_Additional_Data function).
This is how the SOAP request would look like, including all optional parameters.
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<env:Body>
<wd:Edit_Worker_Additional_Data_Request
xmlns:wd="urn:com.workday/bsvc"
wd:version="v28.0">
<wd:Business_Process_Parameters>
<wd:Auto_Complete>true</wd:Auto_Complete>
<wd:Run_Now>true</wd:Run_Now>
<wd:Comment_Data>
<wd:Comment>abcdef</wd:Comment>
<wd:Worker_Reference>
<wd:ID wd:type="Contingent_Worker_ID">abcdef</wd:ID>
</wd:Worker_Reference>
</wd:Comment_Data>
</wd:Business_Process_Parameters>
<wd:Worker_Custom_Object_Data>
<wd:Effective_Date>2017-07-20</wd:Effective_Date>
<wd:Worker_Reference>
<wd:ID wd:type="Contingent_Worker_ID">abcdef</wd:ID>
</wd:Worker_Reference>
<wd:Business_Object_Additional_Data></wd:Business_Object_Additional_Data>
</wd:Worker_Custom_Object_Data>
</wd:Edit_Worker_Additional_Data_Request>
</env:Body>
</env:Envelope>
You have to define the Custom Object (or Additional Data) elements within
<wd:Business_Object_Additional_Data></wd:Business_Object_Additional_Data>
If your Custom Object is defined as "TestObject" for example, you would need both the Object and Field Reference IDs, and it would look like this:
<wd:Business_Object_Additional_Data>
<cus:TestObject>
<cus:TestObjectField>Value</cus:TestObjectField>
</cus:TestObject>
</wd:Business_Object_Additional_Data>
If you are using Java, here is an example usage of the Workday API to update worker data. This is not the Edit_Worker_Additional_Data, but they all work very similar and maybe this code snippet will help someone get started. All of the Java classes here are generated from the wsdl using jaxws-maven-plugin, except for WorkdayCredentials class, see Workday Soap API - User Name/Password for that.
public void updateWorkerContactInfo(Worker worker) throws WorkerDataException,
WorkerDataInvalidException {
HumanResourcesPort hrPort = hrService.getHumanResources();
BindingProvider bp = (BindingProvider) hrPort;
WorkdayCredentials.addWorkdayCredentials(bp,
config.getWdIntegrationUsername(),
config.getWdIntegrationPassword());
MaintainContactInformationForPersonEventRequestType body
= new MaintainContactInformationForPersonEventRequestType();
body.setAddOnly(false);
BusinessProcessParametersType params = new BusinessProcessParametersType();
params.setAutoComplete(false);
params.setRunNow(false);
body.setBusinessProcessParameters(params);
ContactInformationForPersonEventDataType contactData
= new ContactInformationForPersonEventDataType();
edu.bowdoin.workdayservice.data.hr.WorkerObjectType workerObjectType
= new edu.bowdoin.workdayservice.data.hr.WorkerObjectType();
edu.bowdoin.workdayservice.data.hr.WorkerObjectIDType idType
= new edu.bowdoin.workdayservice.data.hr.WorkerObjectIDType();
idType.setType("Employee_ID");
idType.setValue(worker.getWorkerId());
workerObjectType.getID().add(idType);
contactData.setWorkerReference(workerObjectType);
Date effectiveDate = new Date();
// set the effective date to the hire date + 1 day, this has to be
// greater than any other change to the worker address data, for
// example during the new hire process
if (worker.getHireDate() != null) {
DateTime hireDate = new DateTime(worker.getHireDate());
DateTime hireDatePlus1Day = hireDate.plusDays(1);
DateTime today = DateTime.now();
// only use hire date plus 1 if it is after today's date
if (hireDatePlus1Day.isAfter(today)) {
effectiveDate = hireDatePlus1Day.toDate();
}
}
contactData.setEffectiveDate(dateToXMLGregorian(effectiveDate));
ContactInformationDataType contactDataType
= new ContactInformationDataType();
EmailAddressInformationDataType emailAddressDataType
= new EmailAddressInformationDataType();
emailAddressDataType.setEmailAddress(worker.getPrimaryWorkEmail());
CommunicationMethodUsageInformationDataType usageDataType
= new CommunicationMethodUsageInformationDataType();
usageDataType.setPublic(true);
CommunicationUsageTypeDataType usageTypeData
= new CommunicationUsageTypeDataType();
usageTypeData.setPrimary(true);
CommunicationUsageTypeObjectType usageTypeObjectType
= new CommunicationUsageTypeObjectType();
CommunicationUsageTypeObjectIDType usageTypeObjectID
= new CommunicationUsageTypeObjectIDType();
usageTypeObjectID.setType("Communication_Usage_Type_ID");
usageTypeObjectID.setValue("WORK");
usageTypeObjectType.getID().add(usageTypeObjectID);
usageTypeData.setTypeReference(usageTypeObjectType);
usageDataType.getTypeData().add(usageTypeData);
emailAddressDataType.getUsageData().add(usageDataType);
contactDataType.getEmailAddressData().add(emailAddressDataType);
contactData.setWorkerContactInformationData(contactDataType);
body.setMaintainContactInformationData(contactData);
try {
hrPort.maintainContactInformation(body);
} catch (edu.bowdoin.workdayservice.data.hr.ProcessingFaultMsg e) {
throw new WorkerDataException(e.getMessage(), e);
} catch (edu.bowdoin.workdayservice.data.hr.ValidationFaultMsg e) {
throw new WorkerDataInvalidException(e.getMessage(), e);
} finally {
}
}

transform mule message payload to snmp trap or pdu object

I've applied a sample of using snmp4j for sending and receiving traps and everything is ok.
but the issue is :
when using mule esb for receiving snmp traps, I can't convert the incoming message payload to PDU (or any snmp4j suitable object) to extract data from, I've done a lot of search but in vain.
can anyone assist me to :
convert mule esb message payload that I've received from udp endpoint to org.snmp4j.PDU object to extract trap data from?
here is my code :
public synchronized MuleEvent process(MuleEvent event) throws MuleException {
byte[] encodedMessage = event.getMessage().getPayload(byte[].class);
//next line is not working but its only sample of what I Am looking for
PDU pdu = new PDU(encodedMessage );
.....
any assistance is highly appreciated
public class SNMP4JParser implements Callable {
/**
* The following objects are all necessary in order to use SNMP4j as a parser for raw messages.
* This was all inspired by SNMP4j source code, in particular MessageDispatcherImpl.java
*/
private MessageProcessingModel model = null;
private MessageDispatcher dispatcher = null;
private Address listenAddress = null;
private Integer32 messageProcessingModel = null;
private Integer32 securityModel = null;
private OctetString securityName = null;
private Integer32 securityLevel = null;
private PduHandle handle = null;
private StatusInformation statusInfo = null;
private MutableStateReference mutableStateReference = null;
/**
* Taken from org.snmp4j.transport.AbstractTransportMapping class
*/
protected Integer32 maxInboundMessageSize = new Integer32 ( (1 << 16) - 1 );
/**
* Taken from org.snmp4j.MessageDispatcherImpl class
*/
private int transactionID = new Random().nextInt(Integer.MAX_VALUE - 2) + 1;
/**
* Create all objects that SNMP4j needs to parse a raw SNMP message
*/
public SNMP4JParser()
{
model = new MPv1();
dispatcher = new MessageDispatcherImpl();
listenAddress = GenericAddress.parse("udp:0.0.0.0/2001");
messageProcessingModel = new Integer32();
securityModel = new Integer32();
securityName = new OctetString();
securityLevel = new Integer32();
handle = new PduHandle(transactionID);
statusInfo = new StatusInformation();
mutableStateReference = new MutableStateReference();
}
/**
* #see org.mule.api.lifecycle.Callable#onCall(org.mule.api.MuleEventContext)
*/
#Override
public Object onCall(MuleEventContext eventContext) throws Exception
{
byte[] payloadBytes = eventContext.getMessage().getPayloadAsBytes();
ByteBuffer buffer = ByteBuffer.wrap(payloadBytes);
BERInputStream wholeMessage = new BERInputStream(buffer);
MutablePDU mutablePdu = new MutablePDU();
int status = model.prepareDataElements(
dispatcher,
listenAddress,
wholeMessage,
messageProcessingModel,
securityModel,
securityName,
securityLevel,
mutablePdu,
handle,
maxInboundMessageSize,
statusInfo,
mutableStateReference);
if ( status != SnmpConstants.SNMP_MP_OK )
throw new RuntimeException(
"Couldn't parse SNMP message. model.prepareDataElements() returned " + status);
return mutablePdu.getPdu();
}
}
I've tested it with a flow like this ( I used snmp4j-1.11.5 and mule-standalone-3.4.0 )
<udp:connector name="connector" doc:name="UDP"/>
<flow name="snmp-demo-trapHandlingFlow" doc:name="snmp-demo-trapHandlingFlow">
<udp:inbound-endpoint host="0.0.0.0" port="2001" responseTimeout="10000" doc:name="UDP"/>
<logger message="TRAP RECEIVED - #[System.currentTimeMillis()]" level="DEBUG" doc:name="Inbound timestamp"/>
<component class="com.netboss.flow.demo.SNMP4JParser" doc:name="SNMP4JParser"/>
[...]
And it works.
Now, I realize there are still some open questions:
Is there a better/more efficient way of doing it?
This works only for SNMP v1, how do I modify the above code to make it work with v2 and v3 as well?
You can convert a BER stream to a SNMP4J PDU much easier when you implement your own TransportMapping and associate that with the SNMP4J MessageDispatcherImpl. Then add all the necessary MessageProcessingModels and SecurityProtocols to the message dispatcher.
Finally, add your implementation of the CommandResponder interface to the message dispatcher and you are done.
You need to create a custom transformer that transforms the message payload in the relevant SNMP4J object. Alternatively this can be done with an expression transformer if the SNMP4J API is simple enough.

How to send enum in to some method in REST?

I need to write some method that can be called using REST ( using 'Post' ).
This method need to get two parameters
a- some enum
b- some int
Is it sending possible to send this enum parameters ? If it is so how can i do it ?
Please find a sample for the above scenario:
[WebInvoke(UriTemplate = "GetEnumValues/{id}")]
string GetEnumValues(MyEnum e, string id);
public enum MyEnum
{
Fail = 0,
Success = 1
}
Now the request looks as follows when performing the post from fiddler:
URL : http://localhost/Sample/Service1.svc/GetEnumValue/5
User-Agent: Fiddler
Content-Type: application/xml
Host: localhost
<MyEnum xmlns="http://schemas.datacontract.org/2004/07/XMLService">Success</MyEnum>
NOTE: The parameter id is mapped as string as any parameter that is part of the query string needs to be a string type and then u can cast it to an int in your service implementation.
If you want to send both Enum and Id as part of request body then see below:
[WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string GetEnumValuesWrapped(MyEnum e, int id);
Now your requset looks as follows:
URL:http://localhost/Sample/Service1.svc/GetEnumValuesWrapped
User-Agent: Fiddler
Content-Type: application/xml
Host: localhost
<GetEnumValuesWrapped xmlns="http://tempuri.org/"><MyEnum xmlns="http://schemas.datacontract.org/2004/07/XMLService">Success</MyEnum><int xmlns="http://schemas.microsoft.com/2003/10/Serialization/">5</int></GetEnumValuesWrapped>