Home | History | Annotate | Download | only in time
      1 /*
      2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 /*
     27  * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
     28  *
     29  * All rights reserved.
     30  *
     31  * Redistribution and use in source and binary forms, with or without
     32  * modification, are permitted provided that the following conditions are met:
     33  *
     34  *  * Redistributions of source code must retain the above copyright notice,
     35  *    this list of conditions and the following disclaimer.
     36  *
     37  *  * Redistributions in binary form must reproduce the above copyright notice,
     38  *    this list of conditions and the following disclaimer in the documentation
     39  *    and/or other materials provided with the distribution.
     40  *
     41  *  * Neither the name of JSR-310 nor the names of its contributors
     42  *    may be used to endorse or promote products derived from this software
     43  *    without specific prior written permission.
     44  *
     45  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     46  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     47  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     48  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     49  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     50  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     51  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     52  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     53  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     54  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     55  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     56  */
     57 package java.time;
     58 
     59 import java.io.Externalizable;
     60 import java.io.IOException;
     61 import java.io.InvalidClassException;
     62 import java.io.ObjectInput;
     63 import java.io.ObjectOutput;
     64 import java.io.StreamCorruptedException;
     65 
     66 /**
     67  * The shared serialization delegate for this package.
     68  *
     69  * @implNote
     70  * This class wraps the object being serialized, and takes a byte representing the type of the class to
     71  * be serialized.  This byte can also be used for versioning the serialization format.  In this case another
     72  * byte flag would be used in order to specify an alternative version of the type format.
     73  * For example {@code LOCAL_DATE_TYPE_VERSION_2 = 21}.
     74  * <p>
     75  * In order to serialize the object it writes its byte and then calls back to the appropriate class where
     76  * the serialization is performed.  In order to deserialize the object it read in the type byte, switching
     77  * in order to select which class to call back into.
     78  * <p>
     79  * The serialization format is determined on a per class basis.  In the case of field based classes each
     80  * of the fields is written out with an appropriate size format in descending order of the field's size.  For
     81  * example in the case of {@link LocalDate} year is written before month.  Composite classes, such as
     82  * {@link LocalDateTime} are serialized as one object.
     83  * <p>
     84  * This class is mutable and should be created once per serialization.
     85  *
     86  * @serial include
     87  * @since 1.8
     88  */
     89 final class Ser implements Externalizable {
     90 
     91     /**
     92      * Serialization version.
     93      */
     94     private static final long serialVersionUID = -7683839454370182990L;
     95 
     96     static final byte DURATION_TYPE = 1;
     97     static final byte INSTANT_TYPE = 2;
     98     static final byte LOCAL_DATE_TYPE = 3;
     99     static final byte LOCAL_TIME_TYPE = 4;
    100     static final byte LOCAL_DATE_TIME_TYPE = 5;
    101     static final byte ZONE_DATE_TIME_TYPE = 6;
    102     static final byte ZONE_REGION_TYPE = 7;
    103     static final byte ZONE_OFFSET_TYPE = 8;
    104     static final byte OFFSET_TIME_TYPE = 9;
    105     static final byte OFFSET_DATE_TIME_TYPE = 10;
    106     static final byte YEAR_TYPE = 11;
    107     static final byte YEAR_MONTH_TYPE = 12;
    108     static final byte MONTH_DAY_TYPE = 13;
    109     static final byte PERIOD_TYPE = 14;
    110 
    111     /** The type being serialized. */
    112     private byte type;
    113     /** The object being serialized. */
    114     private Object object;
    115 
    116     /**
    117      * Constructor for deserialization.
    118      */
    119     public Ser() {
    120     }
    121 
    122     /**
    123      * Creates an instance for serialization.
    124      *
    125      * @param type  the type
    126      * @param object  the object
    127      */
    128     Ser(byte type, Object object) {
    129         this.type = type;
    130         this.object = object;
    131     }
    132 
    133     //-----------------------------------------------------------------------
    134     /**
    135      * Implements the {@code Externalizable} interface to write the object.
    136      * @serialData
    137      *
    138      * Each serializable class is mapped to a type that is the first byte
    139      * in the stream.  Refer to each class {@code writeReplace}
    140      * serialized form for the value of the type and sequence of values for the type.
    141      * <ul>
    142      * <li><a href="../../serialized-form.html#java.time.Duration">Duration.writeReplace</a>
    143      * <li><a href="../../serialized-form.html#java.time.Instant">Instant.writeReplace</a>
    144      * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate.writeReplace</a>
    145      * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime.writeReplace</a>
    146      * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime.writeReplace</a>
    147      * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay.writeReplace</a>
    148      * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime.writeReplace</a>
    149      * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime.writeReplace</a>
    150      * <li><a href="../../serialized-form.html#java.time.Period">Period.writeReplace</a>
    151      * <li><a href="../../serialized-form.html#java.time.Year">Year.writeReplace</a>
    152      * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth.writeReplace</a>
    153      * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId.writeReplace</a>
    154      * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset.writeReplace</a>
    155      * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime.writeReplace</a>
    156      * </ul>
    157      *
    158      * @param out  the data stream to write to, not null
    159      */
    160     @Override
    161     public void writeExternal(ObjectOutput out) throws IOException {
    162         writeInternal(type, object, out);
    163     }
    164 
    165     static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
    166         out.writeByte(type);
    167         switch (type) {
    168             case DURATION_TYPE:
    169                 ((Duration) object).writeExternal(out);
    170                 break;
    171             case INSTANT_TYPE:
    172                 ((Instant) object).writeExternal(out);
    173                 break;
    174             case LOCAL_DATE_TYPE:
    175                 ((LocalDate) object).writeExternal(out);
    176                 break;
    177             case LOCAL_DATE_TIME_TYPE:
    178                 ((LocalDateTime) object).writeExternal(out);
    179                 break;
    180             case LOCAL_TIME_TYPE:
    181                 ((LocalTime) object).writeExternal(out);
    182                 break;
    183             case ZONE_REGION_TYPE:
    184                 ((ZoneRegion) object).writeExternal(out);
    185                 break;
    186             case ZONE_OFFSET_TYPE:
    187                 ((ZoneOffset) object).writeExternal(out);
    188                 break;
    189             case ZONE_DATE_TIME_TYPE:
    190                 ((ZonedDateTime) object).writeExternal(out);
    191                 break;
    192             case OFFSET_TIME_TYPE:
    193                 ((OffsetTime) object).writeExternal(out);
    194                 break;
    195             case OFFSET_DATE_TIME_TYPE:
    196                 ((OffsetDateTime) object).writeExternal(out);
    197                 break;
    198             case YEAR_TYPE:
    199                 ((Year) object).writeExternal(out);
    200                 break;
    201             case YEAR_MONTH_TYPE:
    202                 ((YearMonth) object).writeExternal(out);
    203                 break;
    204             case MONTH_DAY_TYPE:
    205                 ((MonthDay) object).writeExternal(out);
    206                 break;
    207             case PERIOD_TYPE:
    208                 ((Period) object).writeExternal(out);
    209                 break;
    210             default:
    211                 throw new InvalidClassException("Unknown serialized type");
    212         }
    213     }
    214 
    215     //-----------------------------------------------------------------------
    216     /**
    217      * Implements the {@code Externalizable} interface to read the object.
    218      * @serialData
    219      *
    220      * The streamed type and parameters defined by the type's {@code writeReplace}
    221      * method are read and passed to the corresponding static factory for the type
    222      * to create a new instance.  That instance is returned as the de-serialized
    223      * {@code Ser} object.
    224      *
    225      * <ul>
    226      * <li><a href="../../serialized-form.html#java.time.Duration">Duration</a> - {@code Duration.ofSeconds(seconds, nanos);}
    227      * <li><a href="../../serialized-form.html#java.time.Instant">Instant</a> - {@code Instant.ofEpochSecond(seconds, nanos);}
    228      * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate</a> - {@code LocalDate.of(year, month, day);}
    229      * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime</a> - {@code LocalDateTime.of(date, time);}
    230      * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime</a> - {@code LocalTime.of(hour, minute, second, nano);}
    231      * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay</a> - {@code MonthDay.of(month, day);}
    232      * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime</a> - {@code OffsetTime.of(time, offset);}
    233      * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime</a> - {@code OffsetDateTime.of(dateTime, offset);}
    234      * <li><a href="../../serialized-form.html#java.time.Period">Period</a> - {@code Period.of(years, months, days);}
    235      * <li><a href="../../serialized-form.html#java.time.Year">Year</a> - {@code Year.of(year);}
    236      * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth</a> - {@code YearMonth.of(year, month);}
    237      * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime</a> - {@code ZonedDateTime.ofLenient(dateTime, offset, zone);}
    238      * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId</a> - {@code ZoneId.of(id);}
    239      * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset</a> - {@code (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));}
    240      * </ul>
    241      *
    242      * @param in  the data to read, not null
    243      */
    244     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    245         type = in.readByte();
    246         object = readInternal(type, in);
    247     }
    248 
    249     static Object read(ObjectInput in) throws IOException, ClassNotFoundException {
    250         byte type = in.readByte();
    251         return readInternal(type, in);
    252     }
    253 
    254     private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
    255         switch (type) {
    256             case DURATION_TYPE: return Duration.readExternal(in);
    257             case INSTANT_TYPE: return Instant.readExternal(in);
    258             case LOCAL_DATE_TYPE: return LocalDate.readExternal(in);
    259             case LOCAL_DATE_TIME_TYPE: return LocalDateTime.readExternal(in);
    260             case LOCAL_TIME_TYPE: return LocalTime.readExternal(in);
    261             case ZONE_DATE_TIME_TYPE: return ZonedDateTime.readExternal(in);
    262             case ZONE_OFFSET_TYPE: return ZoneOffset.readExternal(in);
    263             case ZONE_REGION_TYPE: return ZoneRegion.readExternal(in);
    264             case OFFSET_TIME_TYPE: return OffsetTime.readExternal(in);
    265             case OFFSET_DATE_TIME_TYPE: return OffsetDateTime.readExternal(in);
    266             case YEAR_TYPE: return Year.readExternal(in);
    267             case YEAR_MONTH_TYPE: return YearMonth.readExternal(in);
    268             case MONTH_DAY_TYPE: return MonthDay.readExternal(in);
    269             case PERIOD_TYPE: return Period.readExternal(in);
    270             default:
    271                 throw new StreamCorruptedException("Unknown serialized type");
    272         }
    273     }
    274 
    275     /**
    276      * Returns the object that will replace this one.
    277      *
    278      * @return the read object, should never be null
    279      */
    280     private Object readResolve() {
    281          return object;
    282     }
    283 
    284 }
    285