简体   繁体   中英

How can I deal with “null objects” (not null) using JAXB?

I am writing a software to manage box events. The core classes are BoxEvent , Fight , and Fighter . A box event has a list of all available fighters as well as of fights which contain references to particular fighters.

For the references each Fighter gets a unique ID which is used as @XmlID and is referenced in the list of fights through @XmlIDREF . JAXB (un)marshalling works fine. An XML file looks similar to this one:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<boxEvent>
<fighter uuid="id_efc8c3f6-f95c-424f-a6d4-f9fde1cdd3a1">
    <birthday>1995-08-31</birthday>
    <firstName>Donald</firstName>
    <lastName>Duck</lastName>
    <gender>MALE</gender>
    <weight>62.0</weight>
</fighter>
<fighter uuid="id_356f82d1-14a7-4cce-bf5b-18d6e59eddfe">
    <birthday>1994-08-25</birthday>
    <firstName>Mickey</firstName>
    <lastName>Mouse</lastName>
    <gender>MALE</gender>
    <weight>56.9</weight>
</fighter>
<fighter uuid="id_c4b8d4c9-de24-4bfb-bad8-36a5bd4433b5">
    <birthday>1991-08-12</birthday>
    <firstName>Minnie</firstName>
    <lastName>Mouse</lastName>
    <gender>FEMALE</gender>
    <weight>40.8</weight>
</fighter>
<fights>
    <fighterInBlueCorner>id_356f82d1-14a7-4cce-bf5b-18d6e59eddfe</fighterInBlueCorner>
    <fighterInRedCorner>id_efc8c3f6-f95c-424f-a6d4-f9fde1cdd3a1</fighterInRedCorner>
</fights>
</boxEvent>

Now the problem is that a fight may not yet have two fighters, but only one. This is internally implemented by using a special Fighter object (a null object ) and not null and this special object is not in the list of all boxers (because it is no real boxer, rather an implementation detail). That means: A missing fighter can be marshalled in a fight (because it has an ID since technically speaking it is a Fighter ), but it cannot be unmarshalled, because this ID won't be found in the list of all fighters.

Whereas I already found solutions to store null (eg this question ) I could not find a good one for the "null object".

So my question is: Is it possible to use a @XmlJavaTypeAdapter or any other technique to replace the null object by null for marshalling? And when unmarshalling do the opposite: create this special null object for a missing fighter in one corner?

I am also happy to hear about other ideas how to deal with that problem or if you could point me in the right direction. Thanks!

No, the @XmlJavaTypeAdapter will not fire on nulls. Rather, you should have a "default" of whatever it is you need. Then the unmarshalling code will overwrite the fighter if it is indeed in the XML.

@XmlElement
private Fighter fighter = DEFAULT_FIGHTER_OR_NULL_OR_WHATEVER;

My initial question may have been formulated a bit too complicated – sorry! :) I finally found out by myself how to solve my problem properly – well, by just using a @XmlJavaTypeAdapter in the Fight class. The adapter is incredibly simple and looks as follows:

public class FighterXmlAdapter extends XmlAdapter<Fighter, Fighter> {

  @Override
  public Fighter unmarshal(final Fighter fighter) throws Exception {
    return fighter == null ? NULL_FIGHTER : fighter;
  }

  @Override
  public Fighter marshal(final Fighter fighter) throws Exception {
    return fighter.equals(NULL_FIGHTER) ? null : fighter;
  }

}

So in case only the fighter in the red corner is present, the serialized XML will look like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<boxEvent>
  <fighter uuid="id_efc8c3f6-f95c-424f-a6d4-f9fde1cdd3a1">
    <birthday>1995-08-31</birthday>
    <firstName>Donald</firstName>
    <lastName>Duck</lastName>
    <gender>MALE</gender>
    <weight>62.0</weight>
  </fighter>
  <fighter uuid="id_356f82d1-14a7-4cce-bf5b-18d6e59eddfe">
    <birthday>1994-08-25</birthday>
    <firstName>Mickey</firstName>
    <lastName>Mouse</lastName>
    <gender>MALE</gender>
    <weight>56.9</weight>
  </fighter>
  <fights>
    <fighterInRedCorner>id_efc8c3f6-f95c-424f-a6d4-f9fde1cdd3a1</fighterInRedCorner>
  </fights>
</boxEvent>

That means the internal implementation of the missing fighter is not exposed and when loading the file a NULL_FIGHTER is instantiated. Pretty simple, but took me a while to figure it out ... ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM