How can I serialize a class that implements IDictionary with Newtonsoft.JSON? - json

I am pulling out my hair again. I am working thru possible solutions to my other question here. I have this class:
public class PartViewDTO : IDictionary<string, object>
{
...
}
It is constructed with the details of what fields it should represent - Name, PartNumber, Price, etc. etc.
I am trying to serialize a collection of PartViewDTO's as a response for a web service but I don't want the traditional-dictionary serialization of
[ { "Key": "Key1", "Value": "Value1" }, ...]
Instead I want
{ "Key1": "Value1", ... }
I have tried several variations on applying the JsonDictionaryAttribute to this class:
[Newtonsoft.Json.JsonDictionary(ItemTypeNameHandling=Newtonsoft.Json.TypeNameHandling.Objects)]
public class PartViewDTO : IDictionary<string, object>
But at run-time I get an exception thrown that "PartViewDTO is not a dictionary"
Bottom line - PartViewDTO is a dictionary but I want it to serialize like the keys in the dictionary were properties on the class. I'm returning an IEnumerable < PartViewDTO > of these from web services so I'm hoping an attribute applied to the class itself will clue JSON in on how it should be serialized.
What am I doing wrong?

It turns out JSON.NET does a fine job serializing dictionaries the way I want. The problem is it doesn't recognize that my type IS a dictionary. I ended up writing a custom converter for PartViewDTO which did the dictionary-thing.
All is well now!

Related

deserialize lazylist using jackson

I have a object which uses a org.apache.commons.collections.list.LazyList for one of its fields, which is serialized ti JSON. The JSON looks like this:
"myObject": ["org.apache.commons.collections.list.LazyList", [
{
"attr1": "asdasd",
"attr2": 1234
}
]],
The object field looks like this:
List<MyObject> myObject = ListUtils.lazyList(new ArrayList(), {new MyObject()} as Factory)
However trying to deserialize the above JSON using a Jackson ObjectMapper fails, since it can't find a default constructor for a LazyList - which makes sense. But how can I specify how this field can be deserialized?
Error message:
No default constructor for [collection type; class org.apache.commons.collections.list.LazyList, contains [simple type, class foo.bar.MyObject]]
Bounty-constraints:
To collect the bounty, this question needs to be answered using a custom jackson deserializer - the custom deserializer must not be field specific! Hence no solution using custom implementations of a LazyList for a specific type will answer this question adequately.
The solution below worked on both List and Map collection objects, it might also work on yours.
#JsonDeserialize(contentAs=MyObject.class)
private List<MyObject> myObject = ListUtils.lazyList(new ArrayList(), {new MyObject()} as Factory);

Shared references with json

is it possible to make use of the concept of shared references with JSON as output mode? I read this article http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html), but changing the #Produces on my JAX-RS to JSON forces an endless loop. Basically i want to reduce an object to it`s id:
public class Foo {
private long id;
private String someText;
private Bar bar;
}
I want this to bind instances of this like so:
{
"id": 1234,
"someText": "lorem",
"bar_id": 9876
}
This is what i want to avoid:
{
"id": 1234,
"someText": "lorem",
"bar": {
"id": 9876,
"anotherText": "ipsum"
}
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
With MOXy as your JSON-binding provider the shared references post you referenced (from my blog) will work for JSON just as it does for XML. Since you are using JAX-RS below is an example of configuring MOXy in that environment:
http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
When using #XmlID/#XmlIDREF it is expected that the object being reference by its ID also exist in the document. Since this isn't your use case you would be better off using an XmlAdapter. The XmlAdapter would have a signature similar to:
public class BarAdapter extends XmlAdapter<Integer, Bar> {
...
}
In the XmlAdapter you would be responsible for returning the id from the instance of Bar during the marshal, and for returning an instance of Bar based on the id during an unmarshal.

Jackson Polymorphism Deserialize empty JSON object

I have a Jackson polymorphic question.
I want to deserialize JSON data into polymorphic types. Reading Jackson documentation, I can deserialize JSON data to polymorphic types. However, I have a special case. I have a class structure as follows:
class Supreme {
private String type;
}
class Foo extends Supreme {
public String label;
}
class Bar extends Supreme {
}
Note: Class Bar does not have any other member variable other than the inherited "type" field.
I have transformed that structure to:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property ="type")
#JsonSubTypes({#Type(value = Foo.class, name = "Foo"),#Type(value = Bar.class, name = "Bar") })
class Supreme {
}
class Foo extends Supreme {
public String label;
}
class Bar extends Supreme {
}
String data=
"[{
"type": "Foo",
"label": "abc"
},
{
"type": "Bar"
}]"
If I pass in the above json data like:
new ObjectMapper().readValue(data, new TypeReference<List<Supreme>>());
I get something like "Unable to deserialize class Bar out of the END_TOKEN". And I believe that is because the JsonTypeInfo and JsonSubTypes annotations have parsed "type" property and figured out that the 2nd entity in the array should be mapped to Bar class; however it tries to find "something" after the type property in that 2 entity. In other words, Jackson thinks it is an empty JSON object.
(Note: the above data without the 2nd entry in the array works fine. In other words, we can deserialize to a list containing Foo object since it at least has a property other than "type")
Any idea how to get around this?
By mistake, I was using Jackson 1.5
I bumped to Jackson 1.9 and the exception went away. So there was a bug in Jackson 1.5

List becomes String when Marshalling object to json

I'm getting a pretty strange error when marshalling my object to json. My object is annotated like this.
My class:
#XmlRootElement(name = "myobject")
public class MyObject {
private List<String> contactPersonsForMyObject;
#javax.xml.bind.annotation.XmlElement()
public List<String> getContactPersonsForMyObject() {
return contactPersonsForMyObject;
}
public void setContactPersonsForMyObject(List<String> contactPersonsForMyObject) {
this.contactPersonsForMyObject = contactPersonsForMyObject;
}
}
Everything works fine except for that if the List contactPersonsForMyObject contains only one value it get's marshalled to a string which ofcourse creates problems since the application consuming this expects a list.
The marshalled object:
[
{
"myobject": {
"somethingcool": "amazing",
"contactPersonsForMyObject": [
"test.test#gmail.com",
"test#test.se"
],
"myObjectId": "c85e48730501bfae41e67714c6131b7d"
}
},
{
"myobject": {
"somethingcool": "cool",
"contactPersonsForMyObject":"test#test2.se",
"myObjectId": "c85e48730501bfae41e67714cqwerty"
}
}
]
Why does this happen and how do I force it to create a list with one value?
Try using Jackson to handle processing your objects into JSON, it solved the same array problem for me in the past. If you are using RESTEasy (version 1.2 GA) with Maven, this link should help you get things setup to use Jackson to serialize objects to JSON.
This article also has some useful information for integrating Jackson with RESTEasy. Hope this helps!

Jackson JSON to Java mapping for same attrubute with different data type

I have a JSON object which I don't have control of and want to map it to a Java object which is pre-created.
There is one attribute in the JSON object which can be a URL or it could be a JSONArray.
Class SomeClass {
private URL items;
public URL getURL() {
return items;
}
public void setURL(URL url) {
this.items = url;
}
}
Below is the JSON:
Case A:
{
...
items: http://someurl.abc.com/linktoitems,
...
}
OR
Case B
{
...
items: [
{ "id": id1, "name": name1 },
{ "id": id2, "name": name2 }
]
...
}
If i create the POJO to map for Case A, Case B fails and vice versa. In short, is there a way to map the JSON attribute to the POJO field with different data types? In that case I will create two separate fields in the POJO named,
private URL itemLink;
private Item[] itemList;
It depends on exact details, but if what you are asking is if it is possible to map either JSON String or JSON array into a Java property, yes this can be done.
Obvious way would be to define a custom deserializer which handles both kinds of JSON input.
But it is also possible to define Java type in such a way that it can be constructed both by setting properties (which works from JSON Object) and have a single-String-arg constructor or static single-String-arg factory method marked with #JsonCreator.
Yet another possibility is to use an intermediate type that can deserialized from any JSON: both java.lang.Object and JsonNode ("JSON tree") instances can be created from any JSON. From this value you would need to do manual conversion; most likely in setter, like so:
public void setItems(JsonNode treeRoot) { .... }
What will not work, however, is defining two properties with the same name.
One thing I don't quite follow is how you would convert from List to URL though. So maybe you actually do need two separate internal fields; and setter would just assign to one of those (and getter would return value of just one).