Home | History | Annotate | Download | only in chrono
      1 /*
      2  * Copyright (c) 2012, 2015, 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) 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.chrono;
     58 
     59 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
     60 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
     61 import static java.time.temporal.ChronoField.ERA;
     62 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
     63 import static java.time.temporal.ChronoField.YEAR;
     64 import static java.time.temporal.ChronoField.YEAR_OF_ERA;
     65 import static java.time.temporal.ChronoUnit.DAYS;
     66 import static java.time.temporal.ChronoUnit.MONTHS;
     67 
     68 import java.io.InvalidObjectException;
     69 import java.io.ObjectInputStream;
     70 import java.io.Serializable;
     71 import java.time.Clock;
     72 import java.time.DateTimeException;
     73 import java.time.Instant;
     74 import java.time.LocalDate;
     75 import java.time.Year;
     76 import java.time.ZoneId;
     77 import java.time.format.ResolverStyle;
     78 import java.time.temporal.ChronoField;
     79 import java.time.temporal.TemporalAccessor;
     80 import java.time.temporal.TemporalAdjusters;
     81 import java.time.temporal.TemporalField;
     82 import java.time.temporal.UnsupportedTemporalTypeException;
     83 import java.time.temporal.ValueRange;
     84 import java.util.Arrays;
     85 import java.util.Calendar;
     86 import java.util.List;
     87 import java.util.Locale;
     88 import java.util.Map;
     89 import java.util.TimeZone;
     90 
     91 import sun.util.calendar.CalendarSystem;
     92 import sun.util.calendar.LocalGregorianCalendar;
     93 
     94 /**
     95  * The Japanese Imperial calendar system.
     96  * <p>
     97  * This chronology defines the rules of the Japanese Imperial calendar system.
     98  * This calendar system is primarily used in Japan.
     99  * The Japanese Imperial calendar system is the same as the ISO calendar system
    100  * apart from the era-based year numbering.
    101  * <p>
    102  * Japan introduced the Gregorian calendar starting with Meiji 6.
    103  * Only Meiji and later eras are supported;
    104  * dates before Meiji 6, January 1 are not supported.
    105  * <p>
    106  * The supported {@code ChronoField} instances are:
    107  * <ul>
    108  * <li>{@code DAY_OF_WEEK}
    109  * <li>{@code DAY_OF_MONTH}
    110  * <li>{@code DAY_OF_YEAR}
    111  * <li>{@code EPOCH_DAY}
    112  * <li>{@code MONTH_OF_YEAR}
    113  * <li>{@code PROLEPTIC_MONTH}
    114  * <li>{@code YEAR_OF_ERA}
    115  * <li>{@code YEAR}
    116  * <li>{@code ERA}
    117  * </ul>
    118  *
    119  * @implSpec
    120  * This class is immutable and thread-safe.
    121  *
    122  * @since 1.8
    123  */
    124 public final class JapaneseChronology extends AbstractChronology implements Serializable {
    125 
    126     static final LocalGregorianCalendar JCAL =
    127         (LocalGregorianCalendar) CalendarSystem.forName("japanese");
    128 
    129     // Android-changed: don't use locale to create japanese imperial calendar, as it's not generally
    130     // supported on Android. Use Calendar.getJapaneseImperialInstance() instead. See .createCalendar
    131     // Locale for creating a JapaneseImpericalCalendar.
    132     private static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
    133 
    134     static Calendar createCalendar() {
    135         return Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), LOCALE);
    136     }
    137 
    138     /**
    139      * Singleton instance for Japanese chronology.
    140      */
    141     public static final JapaneseChronology INSTANCE = new JapaneseChronology();
    142 
    143     /**
    144      * Serialization version.
    145      */
    146     private static final long serialVersionUID = 459996390165777884L;
    147 
    148     //-----------------------------------------------------------------------
    149     /**
    150      * Restricted constructor.
    151      */
    152     private JapaneseChronology() {
    153     }
    154 
    155     //-----------------------------------------------------------------------
    156     /**
    157      * Gets the ID of the chronology - 'Japanese'.
    158      * <p>
    159      * The ID uniquely identifies the {@code Chronology}.
    160      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
    161      *
    162      * @return the chronology ID - 'Japanese'
    163      * @see #getCalendarType()
    164      */
    165     @Override
    166     public String getId() {
    167         return "Japanese";
    168     }
    169 
    170     /**
    171      * Gets the calendar type of the underlying calendar system - 'japanese'.
    172      * <p>
    173      * The calendar type is an identifier defined by the
    174      * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
    175      * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
    176      * It can also be used as part of a locale, accessible via
    177      * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
    178      *
    179      * @return the calendar system type - 'japanese'
    180      * @see #getId()
    181      */
    182     @Override
    183     public String getCalendarType() {
    184         return "japanese";
    185     }
    186 
    187     //-----------------------------------------------------------------------
    188     /**
    189      * Obtains a local date in Japanese calendar system from the
    190      * era, year-of-era, month-of-year and day-of-month fields.
    191      * <p>
    192      * The Japanese month and day-of-month are the same as those in the
    193      * ISO calendar system. They are not reset when the era changes.
    194      * For example:
    195      * <pre>
    196      *  6th Jan Showa 64 = ISO 1989-01-06
    197      *  7th Jan Showa 64 = ISO 1989-01-07
    198      *  8th Jan Heisei 1 = ISO 1989-01-08
    199      *  9th Jan Heisei 1 = ISO 1989-01-09
    200      * </pre>
    201      *
    202      * @param era  the Japanese era, not null
    203      * @param yearOfEra  the year-of-era
    204      * @param month  the month-of-year
    205      * @param dayOfMonth  the day-of-month
    206      * @return the Japanese local date, not null
    207      * @throws DateTimeException if unable to create the date
    208      * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
    209      */
    210     @Override
    211     public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
    212         if (era instanceof JapaneseEra == false) {
    213             throw new ClassCastException("Era must be JapaneseEra");
    214         }
    215         return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth);
    216     }
    217 
    218     /**
    219      * Obtains a local date in Japanese calendar system from the
    220      * proleptic-year, month-of-year and day-of-month fields.
    221      * <p>
    222      * The Japanese proleptic year, month and day-of-month are the same as those
    223      * in the ISO calendar system. They are not reset when the era changes.
    224      *
    225      * @param prolepticYear  the proleptic-year
    226      * @param month  the month-of-year
    227      * @param dayOfMonth  the day-of-month
    228      * @return the Japanese local date, not null
    229      * @throws DateTimeException if unable to create the date
    230      */
    231     @Override
    232     public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) {
    233         return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
    234     }
    235 
    236     /**
    237      * Obtains a local date in Japanese calendar system from the
    238      * era, year-of-era and day-of-year fields.
    239      * <p>
    240      * The day-of-year in this factory is expressed relative to the start of the year-of-era.
    241      * This definition changes the normal meaning of day-of-year only in those years
    242      * where the year-of-era is reset to one due to a change in the era.
    243      * For example:
    244      * <pre>
    245      *  6th Jan Showa 64 = day-of-year 6
    246      *  7th Jan Showa 64 = day-of-year 7
    247      *  8th Jan Heisei 1 = day-of-year 1
    248      *  9th Jan Heisei 1 = day-of-year 2
    249      * </pre>
    250      *
    251      * @param era  the Japanese era, not null
    252      * @param yearOfEra  the year-of-era
    253      * @param dayOfYear  the day-of-year
    254      * @return the Japanese local date, not null
    255      * @throws DateTimeException if unable to create the date
    256      * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
    257      */
    258     @Override
    259     public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
    260         return JapaneseDate.ofYearDay((JapaneseEra) era, yearOfEra, dayOfYear);
    261     }
    262 
    263     /**
    264      * Obtains a local date in Japanese calendar system from the
    265      * proleptic-year and day-of-year fields.
    266      * <p>
    267      * The day-of-year in this factory is expressed relative to the start of the proleptic year.
    268      * The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system.
    269      * They are not reset when the era changes.
    270      *
    271      * @param prolepticYear  the proleptic-year
    272      * @param dayOfYear  the day-of-year
    273      * @return the Japanese local date, not null
    274      * @throws DateTimeException if unable to create the date
    275      */
    276     @Override
    277     public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) {
    278         return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear));
    279     }
    280 
    281     /**
    282      * Obtains a local date in the Japanese calendar system from the epoch-day.
    283      *
    284      * @param epochDay  the epoch day
    285      * @return the Japanese local date, not null
    286      * @throws DateTimeException if unable to create the date
    287      */
    288     @Override  // override with covariant return type
    289     public JapaneseDate dateEpochDay(long epochDay) {
    290         return new JapaneseDate(LocalDate.ofEpochDay(epochDay));
    291     }
    292 
    293     @Override
    294     public JapaneseDate dateNow() {
    295         return dateNow(Clock.systemDefaultZone());
    296     }
    297 
    298     @Override
    299     public JapaneseDate dateNow(ZoneId zone) {
    300         return dateNow(Clock.system(zone));
    301     }
    302 
    303     @Override
    304     public JapaneseDate dateNow(Clock clock) {
    305         return date(LocalDate.now(clock));
    306     }
    307 
    308     @Override
    309     public JapaneseDate date(TemporalAccessor temporal) {
    310         if (temporal instanceof JapaneseDate) {
    311             return (JapaneseDate) temporal;
    312         }
    313         return new JapaneseDate(LocalDate.from(temporal));
    314     }
    315 
    316     @Override
    317     @SuppressWarnings("unchecked")
    318     public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) {
    319         return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal);
    320     }
    321 
    322     @Override
    323     @SuppressWarnings("unchecked")
    324     public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) {
    325         return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal);
    326     }
    327 
    328     @Override
    329     @SuppressWarnings("unchecked")
    330     public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) {
    331         return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone);
    332     }
    333 
    334     //-----------------------------------------------------------------------
    335     /**
    336      * Checks if the specified year is a leap year.
    337      * <p>
    338      * Japanese calendar leap years occur exactly in line with ISO leap years.
    339      * This method does not validate the year passed in, and only has a
    340      * well-defined result for years in the supported range.
    341      *
    342      * @param prolepticYear  the proleptic-year to check, not validated for range
    343      * @return true if the year is a leap year
    344      */
    345     @Override
    346     public boolean isLeapYear(long prolepticYear) {
    347         return IsoChronology.INSTANCE.isLeapYear(prolepticYear);
    348     }
    349 
    350     @Override
    351     public int prolepticYear(Era era, int yearOfEra) {
    352         if (era instanceof JapaneseEra == false) {
    353             throw new ClassCastException("Era must be JapaneseEra");
    354         }
    355 
    356         JapaneseEra jera = (JapaneseEra) era;
    357         int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
    358         if (yearOfEra == 1) {
    359             return gregorianYear;
    360         }
    361         if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) {
    362             LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
    363             jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
    364             if (JapaneseChronology.JCAL.validate(jdate)) {
    365                 return gregorianYear;
    366             }
    367         }
    368         throw new DateTimeException("Invalid yearOfEra value");
    369     }
    370 
    371     /**
    372      * Returns the calendar system era object from the given numeric value.
    373      *
    374      * See the description of each Era for the numeric values of:
    375      * {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO},
    376      * {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported.
    377      *
    378      * @param eraValue  the era value
    379      * @return the Japanese {@code Era} for the given numeric era value
    380      * @throws DateTimeException if {@code eraValue} is invalid
    381      */
    382     @Override
    383     public JapaneseEra eraOf(int eraValue) {
    384         return JapaneseEra.of(eraValue);
    385     }
    386 
    387     @Override
    388     public List<Era> eras() {
    389         return Arrays.<Era>asList(JapaneseEra.values());
    390     }
    391 
    392     JapaneseEra getCurrentEra() {
    393         // Assume that the last JapaneseEra is the current one.
    394         JapaneseEra[] eras = JapaneseEra.values();
    395         return eras[eras.length - 1];
    396     }
    397 
    398     //-----------------------------------------------------------------------
    399     @Override
    400     public ValueRange range(ChronoField field) {
    401         switch (field) {
    402             case ALIGNED_DAY_OF_WEEK_IN_MONTH:
    403             case ALIGNED_DAY_OF_WEEK_IN_YEAR:
    404             case ALIGNED_WEEK_OF_MONTH:
    405             case ALIGNED_WEEK_OF_YEAR:
    406                 throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
    407             case YEAR_OF_ERA: {
    408                 // Android-changed: use #createCalendar() to create calendar.
    409                 Calendar jcal = createCalendar();
    410                 int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
    411                 return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR),
    412                         jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
    413                         Year.MAX_VALUE - startYear);
    414             }
    415             case DAY_OF_YEAR: {
    416                 // Android-changed: use #createCalendar() to create calendar.
    417                 Calendar jcal = createCalendar();
    418                 int fieldIndex = Calendar.DAY_OF_YEAR;
    419                 return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
    420                         jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
    421             }
    422             case YEAR:
    423                 return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE);
    424             case ERA:
    425                 return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue());
    426             default:
    427                 return field.range();
    428         }
    429     }
    430 
    431     //-----------------------------------------------------------------------
    432     @Override  // override for return type
    433     public JapaneseDate resolveDate(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
    434         return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle);
    435     }
    436 
    437     @Override  // override for special Japanese behavior
    438     ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
    439         // validate era and year-of-era
    440         Long eraLong = fieldValues.get(ERA);
    441         JapaneseEra era = null;
    442         if (eraLong != null) {
    443             era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA));  // always validated
    444         }
    445         Long yoeLong = fieldValues.get(YEAR_OF_ERA);
    446         int yoe = 0;
    447         if (yoeLong != null) {
    448             yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);  // always validated
    449         }
    450         // if only year-of-era and no year then invent era unless strict
    451         if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) {
    452             era = JapaneseEra.values()[JapaneseEra.values().length - 1];
    453         }
    454         // if both present, then try to create date
    455         if (yoeLong != null && era != null) {
    456             if (fieldValues.containsKey(MONTH_OF_YEAR)) {
    457                 if (fieldValues.containsKey(DAY_OF_MONTH)) {
    458                     return resolveYMD(era, yoe, fieldValues, resolverStyle);
    459                 }
    460             }
    461             if (fieldValues.containsKey(DAY_OF_YEAR)) {
    462                 return resolveYD(era, yoe, fieldValues, resolverStyle);
    463             }
    464         }
    465         return null;
    466     }
    467 
    468     private int prolepticYearLenient(JapaneseEra era, int yearOfEra) {
    469         return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
    470     }
    471 
    472      private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map<TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
    473          fieldValues.remove(ERA);
    474          fieldValues.remove(YEAR_OF_ERA);
    475          if (resolverStyle == ResolverStyle.LENIENT) {
    476              int y = prolepticYearLenient(era, yoe);
    477              long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
    478              long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
    479              return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
    480          }
    481          int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
    482          int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
    483          if (resolverStyle == ResolverStyle.SMART) {  // previous valid
    484              if (yoe < 1) {
    485                  throw new DateTimeException("Invalid YearOfEra: " + yoe);
    486              }
    487              int y = prolepticYearLenient(era, yoe);
    488              JapaneseDate result;
    489              try {
    490                  result = date(y, moy, dom);
    491              } catch (DateTimeException ex) {
    492                  result = date(y, moy, 1).with(TemporalAdjusters.lastDayOfMonth());
    493              }
    494              // handle the era being changed
    495              // only allow if the new date is in the same Jan-Dec as the era change
    496              // determine by ensuring either original yoe or result yoe is 1
    497              if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) {
    498                  throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe);
    499              }
    500              return result;
    501          }
    502          return date(era, yoe, moy, dom);
    503      }
    504 
    505     private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map <TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
    506         fieldValues.remove(ERA);
    507         fieldValues.remove(YEAR_OF_ERA);
    508         if (resolverStyle == ResolverStyle.LENIENT) {
    509             int y = prolepticYearLenient(era, yoe);
    510             long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
    511             return dateYearDay(y, 1).plus(days, DAYS);
    512         }
    513         int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
    514         return dateYearDay(era, yoe, doy);  // smart is same as strict
    515     }
    516 
    517     //-----------------------------------------------------------------------
    518     /**
    519      * Writes the Chronology using a
    520      * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
    521      * @serialData
    522      * <pre>
    523      *  out.writeByte(1);     // identifies a Chronology
    524      *  out.writeUTF(getId());
    525      * </pre>
    526      *
    527      * @return the instance of {@code Ser}, not null
    528      */
    529     @Override
    530     Object writeReplace() {
    531         return super.writeReplace();
    532     }
    533 
    534     /**
    535      * Defend against malicious streams.
    536      *
    537      * @param s the stream to read
    538      * @throws InvalidObjectException always
    539      */
    540     private void readObject(ObjectInputStream s) throws InvalidObjectException {
    541         throw new InvalidObjectException("Deserialization via serialization delegate");
    542     }
    543 }
    544