49

This is a pretty simple request, but I just didn't find a way to do it.

I'm basically trying to set up a role in JAXB which says that whenever an null field is encountered, instead of ignoring it in the output, set it to an empty value. So for the class :

@XMLRootElement
Class Foo {
   Integer num;
   Date date;
….
}

When this has been marshalled into the XML file if the date field is null, my output does not have that element in it. What I want to do is include all the fields in the output; and if they are null, replace them with - say a blank. So the output should be :

<foo>
  <num>123</num>
  <date></date>
</foo>

Thanks,

Jalpesh.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Jalpesh
  • 1,603
  • 2
  • 13
  • 15

5 Answers5

40

Thanks guys for your answers.

Chris Dail - I tried your approach, and it didn't really do what I wanted. JAXB was still ignoring my null values, in spite of defining a default value for my fields.

I did stumble across the answer after somebody in the Jersey forums pointed me to documentation section 2.2.12.8 No Value.

Basically, all I had to do was to add the following to my fields :

@XmlElement(nillable = true) 

Once I added that, JAXB would show up those fields when marshalling them to XML like this:

...
<num>5</num>
<date xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
....
Alex Dean
  • 15,575
  • 13
  • 63
  • 74
Jalpesh
  • 1,603
  • 2
  • 13
  • 15
  • Great question and answer - I've posted a follow-up question here about how to simplify the nil syntax: http://stackoverflow.com/questions/8198945/how-to-set-non-namespaced-nil-and-datatype-attributes-in-jaxb – Alex Dean Nov 24 '11 at 01:56
4

But but but...a empty string is not a valid lexical representation for a date, so you can't do that. i.e., if you generated an XML document with an empty value for a date field, it won't validate properly.

In other words, if your date element has a minOccurs of 1 or more and not nillable, then you absolutely must have (1 or more) dates, which can't be null (or blanks, or other non-values).

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • I used to have the first paragraph of this answer as a comment (thanks to the lovely person who upvoted it!), but I figured it'd be more useful as an answer, now that I've expanded on it a bit. :-) – C. K. Young May 13 '09 at 15:31
  • 1
    Agreed, but i'm not validating the xml, and it doesn't have a schema. Having all the fields present will make it easier for the end consumer to figure out what this xml means. Before you start berating me for not having an xml schema :) I'm using this from within another framework (Jersey) which consumes my data objects and spits out XML/Json using JAXB. So the only control I have is over my data objects. In addition I can see a reason to support null values. Think of a use case where I want to generate a CSV file out of my data object. I could use marshal.marshal(elem, myContentHandler). – Jalpesh May 13 '09 at 16:11
  • The contentHandler would then generate CSV file with the right format, which can only be done if none of my data fields are ignored. – Jalpesh May 13 '09 at 16:11
2

As indicated in the other answer is invalid since it is not a valid date. I had a similar issue where I wanted to handle (same as ) specially. Since you cannot use null, you can use the default value mechanism in JAXB. The following will default the value if none is specified. You can through code detect this special date and handle this exception case.

@XmlElement(defaultValue="1970-01-01T00:00:00.0-00:00")

So it is possible to detected and empty date value but you just cannot use null to do it.

Chris Dail
  • 25,715
  • 9
  • 65
  • 74
1

In MOXy u can specify how the jsonProvider must do its job for JAXB.

So when doing JAX-RS, add following code in your class derived from Application

I used this code on Tomcat 7 with good results. (eclipselink 2.4.1)

@ApplicationPath("/rest")
public class RestApplication extends Application
{

  ...

 public Set< Object> getSingletons()
  {

    HashSet<Object> set = new HashSet<Object>(1);
    set.add( newMoxyJsonProvider());

    return set;
  }


 public static MOXyJsonProvider newMoxyJsonProvider()
  {

    MOXyJsonProvider result = new MOXyJsonProvider();

    //result.setAttributePrefix("@");
    result.setFormattedOutput( false);
    result.setIncludeRoot( false);
    result.setMarshalEmptyCollections( true);
    //result.setValueWrapper("$");

    return result;
  }

On Glassfish 3.1.2 and WAS 8.5 however, newMoxyJsonProvider() is not needed, but then the JAXB provider gets configured by the server. In the case of Glassfish, which comes with MOXy, i witnessed same problems with null values. Did not check yet, but guess the answer is in configuring JAXB at application server level if possible at all.

kleopatra
  • 51,061
  • 28
  • 99
  • 211
0

Try this:

marshal.setListener(new MarshallerListener());

with

public class MarshallerListener extends Marshaller.Listener {

    public static final String BLANK_CHAR = "";

    @Override
    public void beforeMarshal(Object source) {
        super.beforeMarshal(source);
        Field[] fields = source.getClass().getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            try {
                if (f.getType() == String.class && f.get(source) == null) {
                    f.set(source, BLANK_CHAR);
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}
Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49
xudd
  • 1