Coverage Report - org.joda.money.Ser
 
Classes in this File Line Coverage Branch Coverage Complexity
Ser
96%
49/51
83%
10/12
3
 
 1  
 /*
 2  
  *  Copyright 2009-2013 Stephen Colebourne
 3  
  *
 4  
  *  Licensed under the Apache License, Version 2.0 (the "License");
 5  
  *  you may not use this file except in compliance with the License.
 6  
  *  You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  *  Unless required by applicable law or agreed to in writing, software
 11  
  *  distributed under the License is distributed on an "AS IS" BASIS,
 12  
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  *  See the License for the specific language governing permissions and
 14  
  *  limitations under the License.
 15  
  */
 16  
 package org.joda.money;
 17  
 
 18  
 import java.io.Externalizable;
 19  
 import java.io.IOException;
 20  
 import java.io.InvalidClassException;
 21  
 import java.io.InvalidObjectException;
 22  
 import java.io.ObjectInput;
 23  
 import java.io.ObjectOutput;
 24  
 import java.io.StreamCorruptedException;
 25  
 import java.math.BigDecimal;
 26  
 import java.math.BigInteger;
 27  
 
 28  
 /**
 29  
  * A package scoped class used to manage serialization efficiently.
 30  
  * <p>
 31  
  * This class is mutable and intended for use by a single thread.
 32  
  */
 33  
 final class Ser implements Externalizable {
 34  
 
 35  
     /** Type for BigMoney. */
 36  
     static final byte BIG_MONEY = 'B';
 37  
     /** Type for Money. */
 38  
     static final byte MONEY = 'M';
 39  
     /** Type for CurrencyUnit. */
 40  
     static final byte CURRENCY_UNIT = 'C';  // not in use yet
 41  
 
 42  
     /** The type. */
 43  
     private byte type;
 44  
     /** The data object. */
 45  
     private Object object;
 46  
 
 47  
     /**
 48  
      * Constructor for serialization.
 49  
      */
 50  9
     public Ser() {
 51  9
     }
 52  
 
 53  
     /**
 54  
      * Constructor for package.
 55  
      * 
 56  
      * @param type  the type
 57  
      * @param object  the object
 58  
      */
 59  9
     Ser(byte type, Object object) {
 60  9
         this.type = type;
 61  9
         this.object = object;
 62  9
     }
 63  
 
 64  
     //-----------------------------------------------------------------------
 65  
     /**
 66  
      * Outputs the data.
 67  
      *
 68  
      * @serialData One byte type code, then data specific to the type.
 69  
      * @param out  the output stream
 70  
      * @throws IOException if an error occurs
 71  
      */
 72  
     public void writeExternal(ObjectOutput out) throws IOException {
 73  9
         out.writeByte(type);
 74  9
         switch (type) {
 75  
             case BIG_MONEY: {
 76  3
                 BigMoney obj = (BigMoney) object;
 77  3
                 writeBigMoney(out, obj);
 78  3
                 return;
 79  
             }
 80  
             case MONEY: {
 81  3
                 Money obj = (Money) object;
 82  3
                 writeBigMoney(out, obj.toBigMoney());
 83  3
                 return;
 84  
             }
 85  
             case CURRENCY_UNIT: {
 86  3
                 CurrencyUnit obj = (CurrencyUnit) object;
 87  3
                 writeCurrency(out, obj);
 88  3
                 return;
 89  
             }
 90  
         }
 91  0
         throw new InvalidClassException("Joda-Money bug: Serialization broken");
 92  
     }
 93  
 
 94  
     private void writeBigMoney(ObjectOutput out, BigMoney obj) throws IOException {
 95  6
         writeCurrency(out, obj.getCurrencyUnit());
 96  6
         byte[] bytes = obj.getAmount().unscaledValue().toByteArray();
 97  6
         out.writeInt(bytes.length);
 98  6
         out.write(bytes);
 99  6
         out.writeInt(obj.getScale());
 100  6
     }
 101  
 
 102  
     private void writeCurrency(ObjectOutput out, CurrencyUnit obj) throws IOException {
 103  9
         out.writeUTF(obj.getCode());
 104  9
         out.writeShort(obj.getNumericCode());
 105  9
         out.writeShort(obj.getDefaultFractionDigits());
 106  9
     }
 107  
 
 108  
     /**
 109  
      * Outputs the data.
 110  
      *
 111  
      * @param in  the input stream
 112  
      * @throws IOException if an error occurs
 113  
      */
 114  
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
 115  9
         type = in.readByte();
 116  9
         switch (type) {
 117  
             case BIG_MONEY: {
 118  3
                 object = readBigMoney(in);
 119  1
                 return;
 120  
             }
 121  
             case MONEY: {
 122  3
                 object = new Money(readBigMoney(in));
 123  1
                 return;
 124  
             }
 125  
             case CURRENCY_UNIT: {
 126  3
                 object = readCurrency(in);
 127  1
                 return;
 128  
             }
 129  
         }
 130  0
         throw new StreamCorruptedException("Serialization input has invalid type");
 131  
     }
 132  
 
 133  
     private BigMoney readBigMoney(ObjectInput in) throws IOException {
 134  6
         CurrencyUnit currency = readCurrency(in);
 135  2
         byte[] bytes = new byte[in.readInt()];
 136  2
         in.readFully(bytes);
 137  2
         BigDecimal bd = new BigDecimal(new BigInteger(bytes), in.readInt());
 138  2
         BigMoney bigMoney = new BigMoney(currency, bd);
 139  2
         return bigMoney;
 140  
     }
 141  
 
 142  
     private CurrencyUnit readCurrency(ObjectInput in) throws IOException {
 143  9
         String code = in.readUTF();
 144  9
         CurrencyUnit singletonCurrency = CurrencyUnit.of(code);
 145  9
         if (singletonCurrency.getNumericCode() != in.readShort()) {
 146  3
             throw new InvalidObjectException("Deserialization found a mismatch in the numeric code for currency " + code);
 147  
         }
 148  6
         if (singletonCurrency.getDefaultFractionDigits() != in.readShort()) {
 149  3
             throw new InvalidObjectException("Deserialization found a mismatch in the decimal places for currency " + code);
 150  
         }
 151  3
         return singletonCurrency;
 152  
     }
 153  
 
 154  
     /**
 155  
      * Returns the object that will replace this one.
 156  
      * 
 157  
      * @return the read object, should never be null
 158  
      */
 159  
     private Object readResolve() {
 160  3
         return object;
 161  
     }
 162  
 
 163  
 }