Java XMLEncoder Enum behavior unexpected

381 Views Asked by At

I have run into what I think is a problem with enums and the XMLEncoder.

The enums are only being correctly encoded once so my output is like:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_72" class="java.beans.XMLDecoder">
 <array class="com.btech.Card" length="52">
  <void index="0">
   <object class="com.btech.Card">
    <void property="cardSuit">
     <object class="java.lang.Enum" id="Card$CardSuit0" method="valueOf">
      <class>com.btech.Card$CardSuit</class>
      <string>DIAMOND</string>
     </object>
    </void>
    <void property="cardValue">
     <object class="java.lang.Enum" id="Card$CardValue0" method="valueOf">
      <class>com.btech.Card$CardValue</class>
      <string>TWO</string>
     </object>
    </void>
   </object>
  </void>
  <void index="1">
   <object class="com.btech.Card">
    <void property="cardSuit">
     <object class="java.lang.Enum" id="Card$CardSuit1" method="valueOf">
      <class>com.btech.Card$CardSuit</class>
      <string>HEART</string>
     </object>
    </void>
    <void property="cardValue">
     <object idref="Card$CardValue0"/>
    </void>
   </object>
  </void>
...

Notice the second card, the cardValue property is not fully expanding enum. I would expect it to be:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_72" class="java.beans.XMLDecoder">
 <array class="com.btech.Card" length="52">
  <void index="0">
   <object class="com.btech.Card">
    <void property="cardSuit">
     <object class="java.lang.Enum" id="Card$CardSuit0" method="valueOf">
      <class>com.btech.Card$CardSuit</class>
      <string>DIAMOND</string>
     </object>
    </void>
    <void property="cardValue">
     <object class="java.lang.Enum" id="Card$CardValue0" method="valueOf">
      <class>com.btech.Card$CardValue</class>
      <string>TWO</string>
     </object>
    </void>
   </object>
  </void>
  <void index="1">
   <object class="com.btech.Card">
    <void property="cardSuit">
     <object class="java.lang.Enum" id="Card$CardSuit1" method="valueOf">
      <class>com.btech.Card$CardSuit</class>
      <string>HEART</string>
     </object>
    </void>
    <void property="cardValue">
     <object class="java.lang.Enum" id="Card$CardValue0" method="valueOf">
      <class>com.btech.Card$CardValue</class>
      <string>TWO</string>
     </object>
    </void>
   </object>
  </void>
...

Are my expectations wrong? Is this the way enums are supposed to behave? I have seen some stuff on how singletons need special encoding, is that the case with enums?

The code to reproduce this is as follows. I have a base card class with a couple of enums:

import java.io.Serializable;

public class Card implements Serializable {
   CardValue cardValue;
   CardSuit cardSuit;

   /**
    * Default constructor for serialization
    */
   public Card() {

   }

   /**
    * Convenience constructor
    */
   public Card(CardValue cardValue, CardSuit cardSuit) {
      this.cardValue = cardValue;
      this.cardSuit = cardSuit;
   }

   public CardValue getCardValue() {
      return cardValue;
   }

   public void setCardValue(CardValue cardValue) {
      this.cardValue = cardValue;
   }

   public CardSuit getCardSuit() {
      return cardSuit;
   }

   public void setCardSuit(CardSuit cardSuit) {
      this.cardSuit = cardSuit;
   }

   @Override
   public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;

      Card card = (Card) o;

      if (cardSuit != card.cardSuit) return false;
      if (cardValue != card.cardValue) return false;

      return true;
   }

   @Override
   public int hashCode() {
      int result = cardValue.hashCode();
      result = 31 * result + cardSuit.hashCode();
      return result;
   }

   public enum CardSuit {
      DIAMOND,
      HEART,
      SPADE,
      CLUB,
      UNSUITED
   }

   public enum CardValue {
      TWO("2"),
      THREE("3"),
      FOUR("4"),
      FIVE("5"),
      SIX("6"),
      SEVEN("7"),
      EIGHT("8"),
      NINE("9"),
      TEN("10"),
      JACK("J"),
      QUEEN("Q"),
      KING("K"),
      ACE("A"),
      JOKER("*");

      private String cardValue;

      private CardValue(String cardValue) {
         this.cardValue = cardValue;
      }

      /**
       * This returns a simple string representation of a card object, may not
       * be suitable for all user interfaces
       *
       * @return - simple 1 or 2 character string representation of the card
       */
      public String getCardValue() {
         return cardValue;
      }

   }

}

And a Deck class:

import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.ArrayList;

public class CardDeck implements Serializable
{
    public static void main( String[] args )
    {
        CardDeck deck = new CardDeck();
        System.out.println( deck.printXML() );
    }

    ArrayList<Card> cards;

    public CardDeck()
    {
        initialize();
    }

    public void initialize() {
        this.cards = new ArrayList<Card>();
        for(Card.CardValue cardValue: Card.CardValue.values()) {
            // Want all cards but the JOKER
            if(cardValue != Card.CardValue.JOKER) {
                for(Card.CardSuit cardSuit: Card.CardSuit.values()) {
                    // Want all suits for each card except UNSUITED
                    if (cardSuit != Card.CardSuit.UNSUITED) {
                        cards.add(new Card(cardValue, cardSuit));
                    }
                }
            }
        }
    }

    public String printXML() {
        String xml;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        XMLEncoder encoder = new XMLEncoder(out);
        encoder.writeObject(cards.toArray(new Card[cards.size()])); // serialize to XML
        encoder.close();
        xml = out.toString(); // stringify

        return xml;
    }

}
0

There are 0 best solutions below