0

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 (e.g. 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!

Community
  • 1
  • 1
philonous
  • 3,621
  • 3
  • 27
  • 24

2 Answers2

0

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;
mvd
  • 2,596
  • 2
  • 33
  • 47
0

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

philonous
  • 3,621
  • 3
  • 27
  • 24