I want to marshal null objects as null in the JSON representation.
But, right now, Am not seeing the element in the JSON if the object is null.
Example:
#XmlAccessType(FIELD)
#XmlType(name="foo" propOrder={"foo"}
class foo{
#XmlElement
private Integer foo;
private Integer another_foo;
..
getter()
setter()
}
In my code am setting foo element to null.
But the JSON representation does not show the element in the response.
The response looks like this
"foo" :{
"another_foo":something
}
I tried setting xml element attribute nillable true. (#XmlElement(nillable=true)
Which makes the response look like,
"foo" :{
"another_foo" : something
"foo":{nil :true}
}
I want it to be like,
"foo" :{
"another_foo":something
"foo" : null
}
What am doing wrong here?
First things first: JAXB does NOT do JSON. It is an XML API. So you are probably using a framework (my guess: JAX-RS implementation like maybe Jersey)? It is necessary to know which one you are using to give more help.
Assuming this, question is, how is the package using JAXB annotations to guide JSON serialization. Some basically convert objects to XML (either logical structure, or full xml), and then convert to JSON using a convention. This may cause data loss because of differences in data model between XML and JSON.
Now: simple solution for most JAX-RS implementations is to not use JAXB annotation based approach at all, but a JSON-specific serializer, such as Jackson's JacksonJsonProvider (Jackson can actually use JAXB annotations, too). It will by default include null values for properties, although this is configurable in case you want to suppress nulls.
Here is JavaDoc that shows how to use Jackson provider (specify FEATURE_POJO_MAPPING for configuration) with Jersey, if that might help.
i think the functionality of json is like that only, it will not show you null values in the Json string. Suppose an example, you have an object with two attributes say age and name. Now if the age is 7 and name is null, then if according to you, name should also be included in the JSON object then, u must right the code to explicit handle the deserialization of the same code. then you will have to handle the null value thing as JSON will treat "null" as a string and will assign it to the object which will make your object with name="null", which is wrong.
If you want to achieve the same, then you must extend the class JSON object and write your own implementation.
Note: I'm the EclipseLink JAXB (MOXy) lead and member of the JAXB (JSR-222) expert group.
EclipseLink JAXB (MOXy) offers native support for JSON. Below is an example of how the #XmlElement annotation can be leveraged to map your use case:
Foo
By default a JAXB implementation will not marshal a null property. You can change this behaviour by setting the nillable property on #XmlElement to true.
package forum3938279;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
class Foo {
#XmlElement(nillable=true)
private Integer foo;
private Integer another_foo;
}
jaxb.properties
To specify MOXy as your JAXB provider you must include a file called jaxb.properties in the same package as your domain model with the following entry:
javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package forum3938279;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Foo foo = new Foo();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("eclipselink.media-type", "application/json");
marshaller.marshal(foo, System.out);
}
}
Output
Below is the output from running the demo code. Both fields had null values. The field without the #XmlElement annotation was not marshalled, and the one with #XmlElement(nillable=true) was marshalled as expected in JSON.
{
"foo" : null
}
For More Information
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
Related
I have a method in a jaxb annotated class that I want to marshall a value if and only if it is marshalling to JSON with jersey 1.16 - which is using jackson 1.9 underneath. I was hoping to use #XmlTransient from jaxb and #JsonProperty from jackson on getting this done in a way like this:
#XmlRootElement
public class SomeClass {
// Other XmlElement annotated methods
#XmlTransient
#JsonProperty(value="type")
public String getType(){
return this.type;
}
}
... but it doesn't seem to marshall at all. No errors are encountered.
I needed to switch Jersey to use the POJOMappingFeature, which uses Jackson.
I needed to not include XmlTransient, otherwise it seemed like the element was ignored. In some cases I believe getType might still be serialized in the XML, however, I was using propOrder in my actual class, and because XmlElement wasn't declared on getType, this wasn't a problem. For those other cases where it may be a problem, I think you'd need to use something like jsonGetType in order to make sure it's not serialized by default.
I am writing a RESTful web service using Java and Jersey, where the service will accept either XML or JSON inputs. Jackson is used as the JSON deserializer, and integrated into the Jersey config.
One of the endpoints is a POST request to a URL, where the content can be one of several different Java classes, and there is a common base class. These classes - with XML annotations - are:
#XmlRootElement(name = "action")
#XmlAccessorType(XmlAccessType.NONE)
#XmlSeeAlso({ FirstAction.class, SecondAction.class, ThirdAction.class })
public abstract class BaseAction {
}
#XmlRootElement(name = "first-action")
#XmlAccessorType(XmlAccessType.NONE)
public class FirstAction extends BaseAction implements Serializable {
}
// Likewise for SecondAction, ThirdAction
In my resource I can declare a method like:
#POST
#Path("/{id}/action")
public Response invokeAction(#PathParam("id") String id, BaseAction action) {...}
Then I can POST an XML fragment that looks like <firstAction/> and my method will be invoked with a FirstAction instance. So far so good.
Where I'm struggling is getting the JSON deserialization to work as seamlessly as the XML deserialization. Where the #XmlSeeAlso annotation was critical to get the XML deserialization working properly, it seemed that the equivalent for JSON was #JsonSubTypes. So I annotated the classes like this:
// XML annotations removed for brevity, but they are present as in the previous code snippet
#JsonSubTypes({ #JsonSubTypes.Type(name = "first-action", value = FirstAction.class),
#JsonSubTypes.Type(name = "second-action", value = SecondAction.class),
#JsonSubTypes.Type(name = "third-action", value = ThirdAction.class) })
public abstract class BaseAction {
}
#JsonRootName("first-action")
public class FirstAction extends BaseAction implements Serializable {
}
// Likewise for SecondAction, ThirdAction
I then feed it my test input: { "first-action": null } but all I can get is:
"org.codehaus.jackson.map.JsonMappingException: Root name 'first-action' does not match expected ('action') for type [simple type, class com.alu.openstack.domain.compute.server.actions.BaseAction]"
Unfortunately since I'm trying to be compatible with someone else's API I can't change my sample input - { "first-action": null } has to work, and deliver to my method an object of class FirstAction. (The action doesn't have any fields, which is why null shouldn't be a problem - it's the type of the class that's important).
What's the correct way to have the JSON deserialization work in the same way as the XML deserialization already is?
If you are using Jackson, you are looking for #JsonTypeInfo and #Type . Please see here for more information
JSON does not work the way XML does, so the solution is not identical.
What you need to use is (like the other answer said), #JsonTypeInfo. That only triggers inclusion and use of the type identifier. If so, then '#JsonSubTypes` will be of use in deserialization.
The reason this indicator must be used is simple: if you have more than one alternative type to deserialize to, there must be something to differentiate.
Note, too, that this does NOT have to be a property -- while most users choose "As.PROPERTY" inclusion, it is not (IMO) the best way. "WRAPPER_OBJECT" may be what you are looking for, as it adds an extra intermediate JSON property, which is somewhat similar to what XML does.
I investigated the use of #JsonTypeInfo but ran into problems because I could not alter the input format. The parser absolutely had to be able to handle input { "first-action":null }. This ruled out the possibility of adding an #type or #class property. Using a wrapper object may have worked, but it choked on the null payload.
A crucial point was that I was using the UNWRAP_ROOT_PROPERTY configuration option. Jackson was absolutely insisting on finding an action property and I could not get it to consider anything else. So, I had to selectively disable UNWRAP_ROOT_PROPERTY for certain domain objects, so that Jackson would be open to parsing alternatives. I modified the project's ContextResolver.getContext(...) implementation to check for a #JsonRootName annotation - since this only has meaning if wrapping is enabled, I used the presence of this annotation to determine whether to return an object mapper configured with root property wrapping on, or off.
At this stage, I might have been able to use #JsonTypeInfo(include=JsonTypeInfo.As.WRAPPER_OBJECT, ...), except for the issue with the null payload mentioned above (this is used to indicate that the child object has no properties - if the spec I was working from had given an empty object {} instead then there would not be a problem). So to proceed I needed a custom type resolver.
I created a new class that extended org.codehaus.jackson.map.TypeDeserializer, with the purpose that whenever Jackson is called to deserialize a BaseAction instance, it will call this custom deserializer. The deserializer will be given a subtypes array, which for BaseAction maps first-action, second-action, etc. to FirstAction.class, etc. The deserializer reads the input stream for the field name, then matches the name to a class. If the next token is an object, then it finds and delegates to the appropriate deserializer for that class, or if it is null it finds the no-args constructor and invokes it to get an object.
A class that implements org.codehaus.jackson.map.jsontype.TypeResolverBuilder is needed that can build an instance of this previous class, and then the TypeResolverBuilder is given as a #JsonTypeResolver annotation on the BaseAction class.
I have to generate a xml element that can have as value any "primitive type" (xsd:string, xsd:boolean, etc). Examples:
<field xsi:type="xsd:string" name="aString">String Value</field>
<field xsi:type="xsd:date" name="aDate">2011-10-21</field>
...
So, I tried two implementations:
public class Field {
#XmlAttribute
private String name;
#XmlValue
Object value;
}
and ...
public class Field<T> {
#XmlAttribute
private String name;
#XmlValue
T value;
}
I'm testing this with:
Marshaller marshaller = JAXBContext.newInstance(Field.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty("com.sun.xml.bind.xmlDeclaration", Boolean.FALSE);
Field field = new Field();
field.name = "name";
field.value = "value";
ByteArrayOutputStream stream = new ByteArrayOutputStream();
marshaller.marshal(field, new PrintWriter(stream));
System.out.println(stream);
But I'm getting this NullPointerException when I try to instantiate the JAXBContext.
java.lang.NullPointerException
at com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.get(TransducedAccessor.java:165)
at com.sun.xml.bind.v2.runtime.property.ValueProperty.<init>(ValueProperty.java:77)
at com.sun.xml.bind.v2.runtime.property.PropertyFactory.create(PropertyFactory.java:106)
at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.<init>(ClassBeanInfoImpl.java:179)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getOrCreate(JAXBContextImpl.java:515)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:330)
at
The idea is allow schema validation for the field element (It is define in a schema must its type will be set in each instance). So, even is this a Bug (or not) ... how JAXB will put the correct xsi:type to this field instance? I'm missing a concept here?
I know that maybe the problem is the usage of the #XmlValue because of this restrictions (from the javadoc):
At most one field or property can be annotated with the #XmlValue annotation.
#XmlValue can be used with the following annotations: XmlList. However this is redundant since XmlList maps a type to a simple schema type that derives by list just as XmlValue would.
If the type of the field or property is a collection type, then the collection item type must map to a simple schema type.
If the type of the field or property is not a collection type, then the type must map to a XML Schema simple type.
... because an Object or a generic T is not necessarily a XML Schema simple type, this approach seems not to be the correct one ...
Thanks in advance ...
I have confirmed the issue you are seeing in both the reference and EclipseLink JAXB (MOXy) implementations of JAXB. The problem you are seeing is due to use of #XmlValue. If the value property was mapped as an #XmlElement you would see the xsi:type attribute appear as expected.
I have entered the following bug to track this issue in EclipseLink JAXB (MOXy):
https://bugs.eclipse.org/361689
Depending upon what your domain model looks like you may be interested in the #XmlPath extension from EclipseLink JAXB (MOXy):
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
UPDATE
This issue has now been fixed in the EclipseLink 2.3.3 and EclipseLink 2.4.0. The fix is available in these streams starting March 17, 2012 and can be obtained from:
http://www.eclipse.org/eclipselink/downloads/nightly.php
Using Jersey and Jackson to create a REST interface, how do I get List fields to be serialized as a list when there are 0 or 1 elements in them. For example:
#XmlRootElement(name="foo")
public class Foo {
#XmlElement
public List<Bar> getBars() {
return this.bars;
}
}
#Path("foo")
public FooResource {
#GET
public Foo getFoo() {
return theFoo;
}
}
When bars has no elements, the result serializes as null and when it contains a single element, it serializes as that element, not an array containing a single element. Is there a way to get these to always serialize as an array?
For reference, I'm using Jersey 1.10 and Jackson 1.9.2.
I am pretty sure that you are not actually using Jackson ("POJO" variant of JSON serialization), since Jackson would not convert single-element arrays or lists to anything else. So you are probably using one of legacy output methods (like jettison); meaning that if you configure system to use POJO mapping it should just work.
I wrote a blog post ages ago about forcing Jersey to serialize single element arrays correctly, not sure if it's out-dated now (its from mid-2010!), but it might be of use.
Note the blog comment from Brill Pappin on the blog demonstrating a different approach which means upgrading the Jettison library that you are using.
In short you can write a custom JaxbContextResolver that looks a little like:
#Provider
#Component
public class JAXBContextResolver implements ContextResolver {
private JAXBContext context;
public JAXBContextResolver() throws Exception {
MappedBuilder builder = JSONConfiguration.mapped();
builder.arrays("invite");
builder.rootUnwrapping(true);
this.context = new JSONJAXBContext(builder.build(), Payload.class);
}
public JAXBContext getContext(Class objectType) {
return (Payload.class.equals(objectType)) ? context : null;
}
}
For clarity, my payload class looked a little like
#XmlRootElement(name = "response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Payload {
#XmlElement(name = "invite")
List invites;
... etc.
Regarding stopping Jackson serializing bean properties as null, see my previous answer here, about using annotations to change that behaviour.
I managed to solve JSON array "bug" in recent Jersey json library (v1.14 Sep 2012). Secret ingredient is JSONConfiguration and ContextResolver magic. See my following post it has a full code example, customized ContextResolver and rest Application class might be somewhat fuzzy logic in first look.
How to serialize Java primitives using Jersey REST
Primitives and zero or single-element List array are properly serialized to JSON document.
Yes, we also faced the same issue. Jackson cannot serialize list with 0 or single element to json array. So we tried to use Json's ObjectMapper to convert POJO object to String. It will serialize java List to json array irrespective of number of elements in List (0 or 1 or > 0). The code would look like :
request = new ObjectMapper().writeValueAsString(pojo);
where request is of type Object. This will not affect response. You can give a try.
Given the XML example:
<fooRoot>
<bar>
<lol>LOLOLOLOL</lol>
</bar>
<noob>
<boon>
<thisIsIt></thisIsIt>
</boon>
</noob>
</fooRoot>
Which should be mapped to:
class MyFoo {
String lol;
String thisIsIt;
Object somethingUnrelated;
}
Constraints:
XML should not be transformed, it is provided as a parsed org.w3c.dom.Document object.
Class does not and will not map 1:1 to the XML.
I'm only interested to map specific paths of the XML to specific fields of the object.
My dream solution would look like:
#XmlMapped
class MyFoo {
#XmlElement("/fooRoot/bar/lol")
String lol;
#XmlElement("/noob/boon/thisIsIt")
String thisIsIt;
#XmlIgnore
Object somethingUnrelated;
}
Does anything likewise exists? What I've found either required a strict 1:1 mapping (e.g. JMX, JAXB) or manual iteration over all fields (e.g. SAX, Commons Digester.)
JiBX binding definitions come the nearest to what I'm lokking for. However, this tool is ment to marshall/unmarshall complete hierarchy of Java objects. I only would like to extract parts of an XML document into an existing Java bean at runtime.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You can do this with MOXy:
#XmlRootElement(name="fooRoot")
class MyFoo {
#XmlPath("bar/lol/text()")
String lol;
#XmlElement("noob/boon/thisIsIt/text()")
String thisIsIt;
#XmlTransient
Object somethingUnrelated;
}
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
Try XStream. It's super easy. Hope it helps! I don't have time now for a full example :)
One option could be write a custom annotation which will take the XPath expression as input and do the bindings.