How to ignore exceptions while deserializing xml to an object - xml-serialization

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

Related

protobuf-net causing Invalid wire type error during deserialization

Working on a POC of transitioning from BinaryFormater to Protobuf for Serialization and deserialization inorder to reduce the deserialization time. While trying to deserialize using the protobuf library I get the following error "Invalid wire-type; this usually means you have over-written a file without truncating or setting the length" while deserializing a file in a rest web API project but the same code runs fine in another web job project with same .Net version.
protobuf-net Version: 3.1.26
.NET version: .NET framework 4.6.2
Seems to be maybe an internal package dependency version issue or issue if the deserialization happens in a w3 process.
Has anyone faced such issues with the protobuf-net package for a REST service.
Below is the code where the ProtoDeserialize function throws a exception Serializer.Deserialize<T>(stream) is called
[ProtoContract]
public class Temp
{
[ProtoMember(1)]
public string name;
[ProtoMember(2)]
public int no;
}
[HttpGet]
public HttpResponseMessage DerserializeProtoBuf()
{
try
{
var x1 = new Temp();
x1.name = "testData";
x1.no = 10;
var data1 = ProtoSerialize<Temp>(x1);
var y = ProtoDeserialize<Temp>(data1); // throws exception
}
catch
{
}
}
public static T ProtoDeserialize<T>(byte[] data) where T : class
{
if (null == data) return null;
try
{
using (var stream = new MemoryStream(data))
{
using (var decompressor = new GZipStream(stream, CompressionMode.Decompress))
{
return Serializer.Deserialize<T>(stream); // throws Invalid wire-type error here
}
}
}
catch(Exception ex)
{
throw new InvalidDataException(String.Format("Invalid data format when proto deserializing {0}", typeof(T).Name), ex);
}
}
public static byte[] ProtoSerialize<T>(T record) where T : class
{
if (null == record) return null;
try
{
using (var stream = new MemoryStream())
{
using (var gZipStream = new GZipStream(stream, CompressionMode.Compress))
{
Serializer.Serialize(gZipStream, record);
}
return stream.ToArray();
}
}
catch(Exception ex)
{
throw new InvalidDataException(String.Format("Invalid data format when proto serializing {0}", typeof(T).Name), ex);
}
}
I have tried adding the package dependencies versions explicilty by adding bindingRedirects.
Have tried updating and degrading the version of protobuf to 2.3.7 and other before versions
Pass decompressor instead of stream to Deserialize. You're passing it the compressed gzip data instead of the decompressed protobuf payload.

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);
}

Spring boot using wrong message convertor

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

Camel mongodb - MongoDbProducer multiple inserts

I am trying to do a multiple insert using the camel mongo db component.
My Pojo representation is :
Person {
String firstName;
String lastName;
}
I have a processor which constructs a valid List of Person pojo and is a valid json structure.
When this list of Person is sent to the mongodb producer , on invocation of createDoInsert the type conversion to BasicDBObject fails. This piece of code below looks to be the problem. Should it have more fall backs / checks in place to attempt the list conversion down further below as it fails on the very first cast itself. Debugging the MongoDbProducer the exchange object being received is a DBList which extends DBObject. This causes the singleInsert flag to remain set at true which fails the insertion below as we get a DBList instead of a BasicDBObject :
if(singleInsert) {
BasicDBObject insertObjects = (BasicDBObject)insert;
dbCol.insertOne(insertObjects);
exchange1.getIn().setHeader("CamelMongoOid", insertObjects.get("_id"));
}
The Camel MongoDbProducer code fragment
private Function<Exchange, Object> createDoInsert() {
return (exchange1) -> {
MongoCollection dbCol = this.calculateCollection(exchange1);
boolean singleInsert = true;
Object insert = exchange1.getIn().getBody(DBObject.class);
if(insert == null) {
insert = exchange1.getIn().getBody(List.class);
if(insert == null) {
throw new CamelMongoDbException("MongoDB operation = insert, Body is not conversible to type DBObject nor List<DBObject>");
}
singleInsert = false;
insert = this.attemptConvertToList((List)insert, exchange1);
}
if(singleInsert) {
BasicDBObject insertObjects = (BasicDBObject)insert;
dbCol.insertOne(insertObjects);
exchange1.getIn().setHeader("CamelMongoOid", insertObjects.get("_id"));
} else {
List insertObjects1 = (List)insert;
dbCol.insertMany(insertObjects1);
ArrayList objectIdentification = new ArrayList(insertObjects1.size());
objectIdentification.addAll((Collection)insertObjects1.stream().map((insertObject) -> {
return insertObject.get("_id");
}).collect(Collectors.toList()));
exchange1.getIn().setHeader("CamelMongoOid", objectIdentification);
}
return insert;
};
}
My route is as below :
<route id="uploadFile">
<from uri="jetty://http://0.0.0.0:9886/test"/>
<process ref="fileProcessor"/>
<unmarshal>
<csv>
<header>fname</header>
<header>lname</header>
</csv>
</unmarshal>
<process ref="mongodbProcessor" />
<to uri="mongodb:mongoBean?database=axs175&collection=insurance&operation=insert" />
and the MongoDBProcessor constructing the List of Person Pojo
#Component
public class MongodbProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
ArrayList<List<String>> personlist = (ArrayList) exchange.getIn().getBody();
ArrayList<Person> persons = new ArrayList<>();
for(List<String> records : personlist){
Person person = new Person();
person.setFname(records.get(0));
person.setLname(records.get(1));
persons.add(person);
}
exchange.getIn().setBody(persons);
}
}
Also requested information here - http://camel.465427.n5.nabble.com/Problems-with-MongoDbProducer-multiple-inserts-tc5792644.html
This issue is now fixed via - https://issues.apache.org/jira/browse/CAMEL-10728

Why am I getting an InvalidCastException with competing Newtonshoft.Json.Linq.[JArray,JObject] with very similar code/data?

This code works fine - returns the single record that matches the REST query:
Popul8TheGrid("http://localhost:28642/api/subdepartments/1/10");
private void Popul8TheGrid(string URIToPass)
{
try
{
dataGridView1.DataSource = GetRESTData(URIToPass);
}
catch (WebException webex)
{
MessageBox.Show("Eek, a mousey-pooh! ({0})", webex.Message);
}
}
private JArray GetRESTData(string uri)
{
var webRequest = (HttpWebRequest) WebRequest.Create(uri);
var webResponse = (HttpWebResponse) webRequest.GetResponse();
var reader = new StreamReader(webResponse.GetResponseStream());
string s = reader.ReadToEnd();
return JsonConvert.DeserializeObject<JArray>(s);
}
However, this code, which also should return a single record:
private const string BASE_URI = "http://localhost:28642/api/";
. . .
string URIToPass = string.Format("{0}deliveryitems/{1}", BASE_URI, numericUpDownDeliveryItemId.Value);
Popul8TheGrid(URIToPass);
...fails, with "InvalidCastException was unhandled ... Message=Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'Newtonsoft.Json.Linq.JArray'".
Why might that be? The data returned from the first (working) snippet comes from an MS Access "database"
The data from the second (failing) snippet is from test data:
public DeliveryItemRepository()
{
// Just some bogus/test data for now
Add(new DeliveryItem
{
Id = 1, InvoiceNumber = "123", UPC_PLU = "456", VendorItemId = "789", PackSize = 1, Description = "Something", Quantity = 5, Cost = 1.25M,
Margin = 0.25M, ListPrice = 1.50M, DepartmentNumber = 42, Subdepartment = "5"
});
. . .
This is the Controller method; it works fine when entering the URI in a browser.
// Enter "http://localhost:28642/api/1"
[Route("api/DeliveryItems/{ID:int}")]
public DeliveryItem GetDeliveryItemById(int ID)
{
return _deliveryItemRepository.GetById(ID);
}
...but why that would matter, I know not...
UPDATE
Interestingly enough (perhaps I'm easily amused), this, OTOH, works:
MessageBox.Show(GetRESTScalarVal("http://localhost:28642/api/deliveries/1"));
. . .
private string GetRESTScalarVal(string uri)
{
var client = new WebClient();
return client.DownloadString(uri);
}
By "works," I mean it returns this:
So DownloadString() will even return an entire json "record" and my use of the word "Scalar" was misleading. Maybe I should have said "Single" instead, although that can be confusing, too, what with the data type of the same appellation.
The question still remains as to how I can populate a datagrid with a single json "record"
UPDATE 2
Oddly enough, if I use a different Controller method to get the one record, it works:
private void GetDeliveryItemById()
{
//string uri = string.Format("deliveryitems/{0}", numericUpDownId.Value);
string uri = string.Format("deliveryitems/{0}/1", numericUpDownId.Value);
Popul8TheGrid(uri);
}
The commented out code is what blows up, whereas the other, with a provided const val of 1, works...kludgy, but it works.
UPDATE 3
Perhaps a clue/related to why it won't work when fetching one, but works otherwise, is this Repository code:
public SiteMapping GetById(int ID)
{
return siteMappings.Find(p => p.Id == ID);
}
public IEnumerable<SiteMapping> GetRange(int ID, int CountToFetch)
{
return siteMappings.Where(i => i.Id >= ID).Take(CountToFetch);
}
If GetById() is called with an ID that exists, it works; if one is passed that doesn't exist, though, it fails with, "InvalidOperationException was unhandled by user code . . . Message=Sequence contains no matching element"
Calling GetRange() works robustly - if passed a bogus pair of vals (no records), it simply shrugs its shoulders, rather than getting the old bulgy eye and screaming maniacally.
Changing it to so (see Simon Whitehead's answere here) works:
public SiteMapping GetById(int ID)
{
var entity = siteMappings.Find(p => p.Id == ID);
return entity == null ? null : entity;
}
So trying to find by a particular ID is fragile; trying to find by ID + Count works just fine. Why, I (still) don't know...
This may be somewhat kludgy, but it works:
private JArray GetRESTData(string uri)
{
try
{
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
var webResponse = (HttpWebResponse)webRequest.GetResponse();
var reader = new StreamReader(webResponse.GetResponseStream());
string s = reader.ReadToEnd();
return JsonConvert.DeserializeObject<JArray>(s);
}
catch // This method crashes if only one json "record" is found - try this:
{
try
{
MessageBox.Show(GetScalarVal(uri));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
return null;
}
private string GetScalarVal(string uri)
{
var client = new WebClient();
return client.DownloadString(uri);
}