Spring boot using wrong message convertor - rest

I have a rest endpoint like below which is supposed to accept an XML input, do some processing on it and then return a response in XML as well.
#RequestMapping(value = "/rest/v1/test/listener", method = RequestMethod.POST)
public ResponseEntity<MyResponseType> processBooking(#RequestBody MyRequest myRequest) throws JAXBException {
MyResponseType response = myService.process(myRequest);
// ... do something with it and generate 'response'
return new ResponseEntity<>(response, HttpStatus.OK);
}
And MyRequest class looks like below which is autogenerated via jaxb and an external xsd which I cannot change (details omitted from the class)
/**
* MyRequest
*/
public class MyRequest {
#XmlElement(required = true)
#XmlSchemaType(name = "string")
protected SomeEnum someEnum;
...
#XmlType(name = "SomeEnum")
#XmlEnum
public enum SomeEnum {
ACTIVITY,
DEPOSIT,
EQUIPMENT,
FEE,
MISC,
PROTECTION,
RENTAL,
TAX,
DISCOUNT;
public static SomeEnum fromValue(String v) {
return valueOf(v);
}
public String value() {
return name();
}
}
}
The problem is that when I try to run it, I get the following error message
2018-04-09 11:47:59.378 WARN 2702 --- [ main]
.w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP
message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Can not construct instance of MyRequest.SomeEnum: no
String-argument constructor/factory method to deserialize from String
value ('MISC'); nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Can not construct
instance of MyRequest.SomeEnum: no String-argument constructor/factory
method to deserialize from String value ('MISC')
A sample xml that I send as input is
<myRequest>
...
<advertiserAssignedId>19ABC12331</advertiserAssignedId>
<listingExternalId>ABC123</listingExternalId>
<unitExternalId>ABC123</unitExternalId>
<someEnum>
<name>MISC</name>
<feeType>MISC</feeType>
...
</someEnum>
...
</myRequest>

You have to specify what is your endpoint consuming using the consumes attribut .
When you post the request to your endpoint, don't forget to set the Content-type header to application/xml

Related

How to ignore exceptions while deserializing xml to an object

I have written a web api which accepts xml and converts to json (a specific object) .
Problem Statement:
If xml contains wrong data type exception is thrown.
Desired situation: xmlserailizer should ignore for the fields where execption is thrown.
following is my sample input xml.
<Invoice>
<ProfileID>bpid:e1212121/ProfileID>
<IssueDate>fault date</IssueDate>
</Invoice>
Following is the code which throws error:
using (var stringreader = new StringReader(requestBody))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(Invoice));
response = (Invoice)xmlSerializer.Deserialize(stringreader);//this line throws error
}
fallowing is my invoice object
public class invoice
{
private string profileID;
private DateTime _IssueDate;
public string ProfileID
{
get{
return this.profileID;
}
set {
this.profileID = value;
}
}
public DateTime IssueDate
{
get{
return this._IssueDate;
}
set {
this._IssueDate; = value;
}
}
}
In summary I want that xmlserialzer ignores error thrown for the fields where the data type is mismatch

Rest Assured: Why do I get IllegalStateException exception?

I am in the process of studying Rest-Assured framework.
I am using http://ziptasticapi.com free API for my drills.
When I call:
final static String BASE_URI = "http://ziptasticapi.com/";
final static String ADAK_ZIP_CODE = "99546"; //{"country":"US","state":"AK","city":"ADAK"}
final static String ATKA_ZIP_CODE = "99547";
public static final String GET_METHOD = "GET";
RestAssured.baseURI = BASE_URI;
String responseString = when().get(ADAK_ZIP_CODE).then()
.statusCode(200)
.and()
.extract()
.asString();
System.out.println(responseString);
I get the following string:
{"country":"US","state":"AK","city":"ADAK"}
as responseString value.
When I am trying:
RestAssured.baseURI = BASE_URI;
ZipData zipdata = when().get(ADAK_ZIP_CODE).then()
.statusCode(200)
.and()
.extract()
.as(ZipData.class);
public class ZipData {
public String country;
public String state;
public String city;
}
I crash on :
java.lang.IllegalStateException: Cannot parse object because no
supported Content-Type was specified in response. Content-Type was
'text/html;charset=UTF-8'.
Why is that? Could it be the rest returns an Html and not Json? How do I handle this?
Thanks!
First of all, keep in mind that REST Assured is a HTTP client primarily designed for testing HTTP APIs. So let me highlight that you shouldn't use REST Assured for anything other than testing.
Looks like the endpoint you are attempting to consume is returning a JSON document in the response payload, but the value of the Content-Type header is text/html;charset=UTF-8, so REST Assured cannot parse the response as a JSON document and convert it to an instance of ZipData. That's not what you expect from a sound HTTP API.
You could work around it and write a filter to override the Content-Type header, as show below:
public class OverrideContentTypeFilter implements Filter {
#Override
public Response filter(FilterableRequestSpecification requestSpec,
FilterableResponseSpecification responseSpec,
FilterContext ctx) {
Response next = ctx.next(requestSpec, responseSpec);
return new ResponseBuilder().clone(next).setContentType(ContentType.JSON).build();
}
}
Then use it as follows:
ZipData zipdata =
given()
.filter(new OverrideContentTypeFilter())
.when()
.get(uri)
.then()
.statusCode(200)
.extract()
.as(ZipData.class);

REST Response is {}

I am new to REST. I have written a small REST resource and Whenever I try to invoke the REST service from POSTMAN, i get a empty response {} and status code 200
The Request :
http://localhost:8080/demo/managers
#GET
#Path("managers")
#Produces({"application/json"})
public Response getManagers() throws GeneralException, JSONException
{
JSONArray valueString = COMING_FROM_OTHER_METHOD();
System.out.println("==== "+valueString.toString());
return Response.ok(valueString,MediaType.APPLICATION_JSON).build();
}
The correct value I can see in System.out.println():
[{"display":"john","id":"003"},{"display":"hansi","id":"004"},{"display":"samy gayle","id":"005"}]
I want to a JSONArray Response but everytime I get an empty response
{}
But when modify the code like below it gives correct response
#GET
#Path("managers")
#Produces({"application/json"})
public String getManagers() throws GeneralException, JSONException
{
JSONArray valueString = COMING_FROM_OTHER_METHOD();
System.out.println("==== "+valueString.toString());
return valueString.toString();
}
Kindly Help. why am I getting {} when trying to return a Response object J
I would use domain objects rather than String instances:
class Manager {
private String id;
private String display;
... setters/getters ...
}
public ResponseEntity<ArrayList<Manager>> getManagers() throws GeneralException {
ArrayList<Manager> managers = COMING_FROM_OTHER_METHOD();
return new ResponseEntity<>(managers, HttpStatus.OK);
}

Is it possible to apply dictionaries for Citrus static response adapter response template?

I'm using Citrus static response adapter to mock services, and I need to change values in its payload for every test case. Ideally I think about usage of dictionaries for each test case. There is sample of my current scenario:
#Autowired
#Qualifier("checkRegistrationEndpointAdapter")
public StaticResponseEndpointAdapter checkRegistrationEndpointAdapter;
protected void setAdapterResponse(StaticResponseEndpointAdapter adapter, String filenamepath){
URL url = this.getClass().getResource(filenamepath);
String payload = null;
try {
payload = Resources.toString(url, Charsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
adapter.setMessagePayload(payload);
}
#CitrusTest
public void TestCase02() throws IOException {
http()
.client(CLIENT)
.post()
.payload(new ClassPathResource("templates/thisStartRequestMsg.xml", getClass()))
.dictionary("TC02");
http()
.client(CLIENT)
.response()
.messageType("xml")
.payload(new ClassPathResource("templates/thisStartResponseMsg.xml", getClass()));
action(new AbstractTestAction() {
#Override
public void doExecute(TestContext testContext) {
setAdapterResponse(checkRegistrationEndpointAdapter, "templates/check-registration-v1CheckRegistrationResponseMsg.xml");
}
});
http()
.client(CLIENT)
.response()
.messageType("xml")
.payload(new ClassPathResource("templates/check-registration-v1CheckRegistrationRequestMsg.xml", getClass()))
.dictionary("TC02");
}
How can I apply dictionary to the payload set in my setAdapterResponse method?
Note: this question relates to Can I use Citrus variable in Citrus static response adapter payload?
Static response adapter has currently no support for data dictionaries. I wonder why you put so much effort into static response adapters? Why not using the full Citrus http server power with receiving the request and providing a response inside the test case?

#ModelAttribute for Rest PUT - request param null

I need to populate my pojo class based on the request param 'type'.
so I have code like
#ModelAttribute
public void getModelObject(HttpServletRequest request, ModelMap modelMap) {
String typeCombo = request.getParameter("type");
System.out.println("typeCombo: " + typeCombo);
if (typeCombo != null) {
if (condition) {
modelMap.addAttribute("modelObj", new ClassB()); //ClassB extends ClassA
} else if (another condition) {
modelMap.addAttribute("modelObj", new ClassC()); //ClassC extends ClassA
} else {
System.out.println("no type found");
}
} else {
System.out.println("typecombo null");
}
}
I use above method to get create correct subclasses which will be used to add / update. The above one works fine in case of "POST" - for creating a record. But for "PUT" request.getParameter("type") always returns null. So for editing, I'm not able to get correct subclasses.
Below are my post and put request mapping:
#RequestMapping(value = "", method = RequestMethod.POST, headers = "Accept=*/*")
#ResponseBody
public String addCredentials(#ModelAttribute("modelObj") Credential credential,
ModelMap modelMap) {
//code
}
#RequestMapping(value = "/edit/{id}", method = RequestMethod.PUT, headers = "Accept=*/*")
#ResponseBody
public Credential editCredential(#ModelAttribute ("modelObj") Credential credential, #PathVariable long id, ModelMap model) {
//code
}
Any help is much appreciated.
Register the filter HttpPutFormContentFilter like this:
<beans:bean id="httpPutFormContentFilter"
class="org.springframework.web.filter.HttpPutFormContentFilter" />