JAXB Marshalling with null fields - java

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.

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"/>
....

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).

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.

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.

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

Related

Solve Sonar issue in simple getter and setter methods with Date or List

I write this getter/setter to list from Eclipse source menu:
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
And Sonar reporting two issues:
Return a copy of "date" & Store a copy of "date"
with the explanation
"Mutable members should not be stored or returned directly"
and a example code:
public String [] getStrings() {
return strings.clone();}
public void setStrings(String [] strings) {
this.strings = strings.clone();}
I think if my Date is null, it will throw a NullPointerException. Then I've changed my code to:
public Date getDate() {
if (this.date != null) {
return new Date(this.date.getTime());
} else {
return null;
}
}
public void setDate(Date date) {
if (date != null) {
this.date = new Date(date.getTime());
} else {
this.date = null;
}
}
And now marks other issue:
"Assigning an Object to null is a code smell. Consider refactoring".
I've searched in internet and set or return a new array is not a solution for me, I want to preserve my list to null if the setter param is null to overwrite an existing previous list.
I've the same problem for List, and I want to return/preserve null instead of a new ArrayList for an empty List. And in this case, the setter marks one more issue:
"Return an empty collection instead of null.".
What is the solution for this issue?
If you are in Java 8 and do not want to handle empty date, then maybe usage of Optional would help you.
Edit: Example of your "POJO" class
public class Toto {
public Optional<Date> myDate;
public Optional<Date> getMyDate() {
return this.myDate;
}
public void setMyDate(final Date myDate) {
this.myDate = Optional.ofNullable(myDate);
}
}
Example of code usage:
Toto toto = new Toto();
toto.setMyDate(null);
System.out.println("Value is null ? " + toto.getMyDate().isPresent());
System.out.println("Value: " + toto.getMyDate().orElse(new Date()));
Try to change the toto.setMyDate(...) with concrete date value to see what happen.
If you don't know what is Optional or how to use it, you can find plenty of examples.
BUT : This is only a way to solve your violation issue and i totally agree with Brad's remark, Optional are not intent to be used as a type, but more like a contract for potential empty / null returns.
In general, you should not correct your code in a bad way just to fix a violation, if the violation is not correct. And in your case i think you should just ignore the violation (as most of Sonar's one unfortunatly)
If you really want to use Java 8 and Optional in your code, then you POJO class would be like this (usage of Optional as a contrat on the getter only)
public class Toto {
public Date myDate;
public Optional<Date> getMyDate() {
return Optional.ofNullable(this.myDate);
}
public void setMyDate(final Date myDate) {
this.myDate = myDate;
}
}
This way,
You bean stay serializable (Optional is not)
You still enable your "client" code to have the choice on how to behave to empty / null value of your property
Configure your Sonar violation as a false positive as it is what you want instead of changing your code
Generally, while using static analysis tools to verify the code is valuable, you should not blindly fix every warnings which popups on you. You need to analyze the issue which is triggered and check if it really applies in your context.
Now to address the issues you are mentioning
Return a copy of "date" & Store a copy of "date"
This seems to be valid one. It is good practice to be defensive and not expose mutable state via getters/setters. So creating a defensive copy in getter/setter should be done. This can be done the way you did it, or by using new Java Time API, which provides immutable objects.
Assigning an Object to null is a code smell. Consider refactoring
IMO dubious one. The issue is raised by PMD plugin (which is the tool analyzing the code, SonarQube is displaying the report). Issue is raised by this rule http://pmd.sourceforge.net/pmd-4.3.0/rules/controversial.html#NullAssignment , as you can see it is in controversial category. I don't think there is anything wrong with your code, and proper action might be to ignore this warning and mark the issue as "won't fix". You can also configure your SonarQube to not use this particular rule in your Quality Profile setting.
Return an empty collection instead of null.
You did not provide the code which is triggering it, but this seems to be a valid piece of advice. It is generally better to return empty collections rather than nulls.
You don't have to explcitly set null in your setter, just use the value being passed in like this...
public void setDate(Date date) {
if (date != null) {
this.date = new Date(date.getTime());
} else {
this.date = date;
}
}
Personally I would never allow null values into my Value objects where ever possible, but that is just my opinionated coding style.
My advice to anyone is to prefer immutable value objects where you set all the values in the constructor and don't allow nulls in. This style may not be appropriate for all 3rd party libraries that expect the java bean getter/setters so be aware where it can be used effectively to simplify your code.
Edit
If the above code still gives you the warning and you must have the "property is not set yet" functionality, another approach is to define a "null object" like this
public static final Date NO_DATE = new Date(Long.MIN_VALUE);
public void setDate(Date date) {
this.date = (date == null) ? NO_DATE : new Date(date.getTime());
}
Users of this class can refer to the NO_DATE object like this, which still makes for readable code
if(toto.getDate() != NO_DATE) ...
Or encapsulate this into another method so it's used like this
if(toto.hasDate()) ...
Of course this doens't add much benefit over the Java 8 Optional approach from #kij but it does work with any version of Java

Java Custom Annotation and dynamic database content

i am trying to implement the Custom Java Annotation :
and wrote following so far:
#Target({ElementType.FIELD,ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MappedField{
boolean isValueRequired() default false;
}
My Requirement is if a property/Method of a Class is isValueRequired=true then it should get the mapped value for this property from database:
For example in my db Salutations are like 01 for MR and 02 for MRS and so on.
And when this annotation is enabled i want property value automatically to be fetched from db:
From other questions i got hint that i need to parse the annotations later something like this:
public static void performAnnotationScanOnClass(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
for ( Field field : fields ) {
Annotation[] annotations = field.getAnnotations();
for (Annotation annotation : annotations) {
if ( annotation instanceof MappedField) {
MappedField mappedField= (MappedField) annotation;
// if ( field.get( ... ) == null )
// field.set( ... , value)
}
but my point is where exactly i need to write this code for parsing the annotations.
Any help would be highly appreciated.
Thanks
A suitable place. You could for example have a factory that creates the instances and fills the values from the database. Then you'll just need to be careful to create all the instances through the factory (or you don't need to, but then you must realize that the annotations won't be processed either).

Jaxb/MOXY ClassExtractor on XmlElement

I'm facing an issue using jaxb, when unmarshalling my xml, I can't manage to make the difference between one of my classes and an inherited one.
I got a 1 st class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlClassExtractor(PersonExtractor.class)
#XmlSeeAlso(Toto.class)
public class Person {
}
An inherited one:
public class Toto
extends Person
{
#XmlElement(name = "additionalInformation")
private String additionalInformation;
}
My extractor:
public class PersonExtractor
extends ClassExtractor
{
#Override
public Class extractClassFromRow(Record pArg0, Session pArg1)
{
if (pArg0.get("additionalInformation") != null || pArg0.get("#additionalInformation") != null)
{
return Toto.class;
}
else
{
return Person.class;
}
}
}
Unfortunately this doesn't works.
When I'm trying to unmarshall Person.class is always returned.
If I change:
#XmlElement(name = "additionalInformation")
into
#XmlAttribute(name = "additionalInformation")
Everything works fine (unfortunately I do want an element).
None of those classes is my root element (everything is "deep" into my model)
Does someone know what I am missing ? probably somthing really dumb, but can't manage to put my hand on it.
Thanks
Probably you have a namespace define for your root element (or default namespace), so the element name is not additionalInformation but namespace:additionalInformation (or however it is represented in the Record element). Have you also checked that content of Toto class is saved correctly witht he additionalInformation element (I guess it was since it works with attribute, but just in case).
You can printout the content of your Record element to see what and how is stored there.
Thanks for the answer, I found a solution:
Apparently currently MOXy requires that the inheritance indicator is in an XML attribute for the #XmlClassExtractor to work.
I ended up finding and using an other way to handle inheritance using #XmlAdapter

Unmarshalling empty tag into new instances of collections

I am trying to unmarshal something like below into their JAXB equivalents, and the fields are as expected being populated with nulls
XML
<University>
<StudentFirstNames/>
</University>
JAXB POJO
public class University {
List<StudentFirstNames> studentFirstNames = null;
public void getStudentFirstNames() {
return studentFirstNames
}
public void setStudentFirstNames() {
this.studentFirsNames = studentFirstNames;
}
}
After unmarshalling I am returned back null when I lookup the member in the JAXB object
university.getStudentFirstNames() --> null
In this specific situation I am trying to resolve, I need to replace empty tags with new instance of that particular type. For example in the above, I am expecting back a new ArrayList () instead of null. I know this sounds counter intuitive but that is what I have to do for satisying code downstream.
Is there a global fix to resolve such instances. Thanks in advance.
You could initialize your field as follows to get the desired behaviour:
List<StudentFirstNames> studentFirstNames = new ArrayList<StudentFirstNames>;
To be able to differentiate between a null and empty collection you will need to use an #XmlElementWrapper annotation.
http://blog.bdoughan.com/2012/12/jaxb-representing-null-and-empty.html

Convert empty string to null using javax.validation annotations

I have the following variable annotated for data validation:
#Size(min=8, max=16, message="the size of the parameter must be between 8 and 16")
private String param;
However, the param can be null. It is required that it be 8-16 chars long only if it is not null. The problem I face is if the client app (JSON API) supplies an empty string, I want to treat it as though it were not supplied at all, i.e. is null. I was wondering if there is an elegant way to do this using the javax.validation annotations, i.e. convert an empty string to null, as opposed to the plain Java way the way I'm doing it right now:
public void setParameter(String _param) {
if(_param != null && !_param.trim().isEmpty()){
this.param = _param;
} else {
this.param = null;
}
}
I would like to have a very simple setter:
public void setParameter(String _param) {
this.param = _param;
}
and have the is-empty-string boilerplate done by an annotation. Is there a way to do it?
You could can implement your own custom constraint validator.
see here. I've used this many times and works like a charm.
https://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html/validator-customconstraints.html
You would just need to set this condition (if null return "" or vice-versa) in the isValid method.

Categories

Resources