Home | History | Annotate | Download | only in charset
      1 /* Licensed to the Apache Software Foundation (ASF) under one or more
      2  * contributor license agreements.  See the NOTICE file distributed with
      3  * this work for additional information regarding copyright ownership.
      4  * The ASF licenses this file to You under the Apache License, Version 2.0
      5  * (the "License"); you may not use this file except in compliance with
      6  * the License.  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 
     17 package java.nio.charset;
     18 
     19 import java.nio.BufferOverflowException;
     20 import java.nio.BufferUnderflowException;
     21 import java.nio.ByteBuffer;
     22 import java.nio.CharBuffer;
     23 
     24 /**
     25  * A converter that can convert a byte sequence from a charset into a 16-bit
     26  * Unicode character sequence.
     27  * <p>
     28  * The input byte sequence is wrapped by a
     29  * {@link java.nio.ByteBuffer ByteBuffer} and the output character sequence is a
     30  * {@link java.nio.CharBuffer CharBuffer}. A decoder instance should be used in
     31  * the following sequence, which is referred to as a decoding operation:
     32  * <ol>
     33  * <li>invoking the {@link #reset() reset} method to reset the decoder if the
     34  * decoder has been used;</li>
     35  * <li>invoking the {@link #decode(ByteBuffer, CharBuffer, boolean) decode}
     36  * method until the additional input is not needed, the <code>endOfInput</code>
     37  * parameter must be set to false, the input buffer must be filled and the
     38  * output buffer must be flushed between invocations;</li>
     39  * <li>invoking the {@link #decode(ByteBuffer, CharBuffer, boolean) decode}
     40  * method for the last time, and then the <code>endOfInput</code> parameter
     41  * must be set to true;</li>
     42  * <li>invoking the {@link #flush(CharBuffer) flush} method to flush the
     43  * output.</li>
     44  * </ol>
     45  * <p>
     46  * The {@link #decode(ByteBuffer, CharBuffer, boolean) decode} method will
     47  * convert as many bytes as possible, and the process won't stop until the input
     48  * bytes have run out, the output buffer has been filled or some error has
     49  * happened. A {@link CoderResult CoderResult} instance will be returned to
     50  * indicate the stop reason, and the invoker can identify the result and choose
     51  * further action, which includes filling the input buffer, flushing the output
     52  * buffer or recovering from an error and trying again.
     53  * <p>
     54  * There are two common decoding errors. One is named malformed and it is
     55  * returned when the input byte sequence is illegal for the current specific
     56  * charset, the other is named unmappable character and it is returned when a
     57  * problem occurs mapping a legal input byte sequence to its Unicode character
     58  * equivalent.
     59  * <p>
     60  * Both errors can be handled in three ways, the default one is to report the
     61  * error to the invoker by a {@link CoderResult CoderResult} instance, and the
     62  * alternatives are to ignore it or to replace the erroneous input with the
     63  * replacement string. The replacement string is "\uFFFD" by default and can be
     64  * changed by invoking {@link #replaceWith(String) replaceWith} method. The
     65  * invoker of this decoder can choose one way by specifying a
     66  * {@link CodingErrorAction CodingErrorAction} instance for each error type via
     67  * {@link #onMalformedInput(CodingErrorAction) onMalformedInput} method and
     68  * {@link #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter}
     69  * method.
     70  * <p>
     71  * This is an abstract class and encapsulates many common operations of the
     72  * decoding process for all charsets. Decoders for a specific charset should
     73  * extend this class and need only to implement the
     74  * {@link #decodeLoop(ByteBuffer, CharBuffer) decodeLoop} method for the basic
     75  * decoding. If a subclass maintains an internal state, it should override the
     76  * {@link #implFlush(CharBuffer) implFlush} method and the
     77  * {@link #implReset() implReset} method in addition.
     78  * <p>
     79  * This class is not thread-safe.
     80  *
     81  * @see java.nio.charset.Charset
     82  * @see java.nio.charset.CharsetEncoder
     83  */
     84 public abstract class CharsetDecoder {
     85 
     86     /*
     87      * internal status consts
     88      */
     89     private static final int INIT = 0;
     90 
     91     private static final int ONGOING = 1;
     92 
     93     private static final int END = 2;
     94 
     95     private static final int FLUSH = 3;
     96 
     97     // average number of chars for one byte
     98     private float averChars;
     99 
    100     // maximum number of chars for one byte
    101     private float maxChars;
    102 
    103     // charset for this decoder
    104     private Charset cs;
    105 
    106     // specify the action if malformed input error encountered
    107     private CodingErrorAction malformAction;
    108 
    109     // specify the action if unmappable character error encountered
    110     private CodingErrorAction unmapAction;
    111 
    112     // the replacement string
    113     private String replace;
    114 
    115     // the current status
    116     private int status;
    117 
    118     /**
    119      * Constructs a new <code>CharsetDecoder</code> using the given
    120      * <code>Charset</code>, average number and maximum number of characters
    121      * created by this decoder for one input byte, and the default replacement
    122      * string "\uFFFD".
    123      *
    124      * @param charset
    125      *            the <code>Charset</code> to be used by this decoder.
    126      * @param averageCharsPerByte
    127      *            the average number of characters created by this decoder for
    128      *            one input byte, must be positive.
    129      * @param maxCharsPerByte
    130      *            the maximum number of characters created by this decoder for
    131      *            one input byte, must be positive.
    132      * @throws IllegalArgumentException
    133      *             if <code>averageCharsPerByte</code> or
    134      *             <code>maxCharsPerByte</code> is negative.
    135      */
    136     protected CharsetDecoder(Charset charset, float averageCharsPerByte,
    137             float maxCharsPerByte) {
    138         if (averageCharsPerByte <= 0 || maxCharsPerByte <= 0) {
    139             throw new IllegalArgumentException("averageCharsPerByte and maxCharsPerByte must be positive");
    140         }
    141         if (averageCharsPerByte > maxCharsPerByte) {
    142             throw new IllegalArgumentException("averageCharsPerByte is greater than maxCharsPerByte");
    143         }
    144         averChars = averageCharsPerByte;
    145         maxChars = maxCharsPerByte;
    146         cs = charset;
    147         status = INIT;
    148         malformAction = CodingErrorAction.REPORT;
    149         unmapAction = CodingErrorAction.REPORT;
    150         replace = "\ufffd";
    151     }
    152 
    153     /**
    154      * Gets the average number of characters created by this decoder for a
    155      * single input byte.
    156      *
    157      * @return the average number of characters created by this decoder for a
    158      *         single input byte.
    159      */
    160     public final float averageCharsPerByte() {
    161         return averChars;
    162     }
    163 
    164     /**
    165      * Gets the <code>Charset</code> which this decoder uses.
    166      *
    167      * @return the <code>Charset</code> which this decoder uses.
    168      */
    169     public final Charset charset() {
    170         return cs;
    171     }
    172 
    173     /**
    174      * This is a facade method for the decoding operation.
    175      * <p>
    176      * This method decodes the remaining byte sequence of the given byte buffer
    177      * into a new character buffer. This method performs a complete decoding
    178      * operation, resets at first, then decodes, and flushes at last.
    179      * <p>
    180      * This method should not be invoked while another {@code decode} operation
    181      * is ongoing.
    182      *
    183      * @param in
    184      *            the input buffer.
    185      * @return a new <code>CharBuffer</code> containing the the characters
    186      *         produced by this decoding operation. The buffer's limit will be
    187      *         the position of the last character in the buffer, and the
    188      *         position will be zero.
    189      * @throws IllegalStateException
    190      *             if another decoding operation is ongoing.
    191      * @throws MalformedInputException
    192      *             if an illegal input byte sequence for this charset was
    193      *             encountered, and the action for malformed error is
    194      *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}
    195      * @throws UnmappableCharacterException
    196      *             if a legal but unmappable input byte sequence for this
    197      *             charset was encountered, and the action for unmappable
    198      *             character error is
    199      *             {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}.
    200      *             Unmappable means the byte sequence at the input buffer's
    201      *             current position cannot be mapped to a Unicode character
    202      *             sequence.
    203      * @throws CharacterCodingException
    204      *             if another exception happened during the decode operation.
    205      */
    206     public final CharBuffer decode(ByteBuffer in)
    207             throws CharacterCodingException {
    208         reset();
    209         int length = (int) (in.remaining() * averChars);
    210         CharBuffer output = CharBuffer.allocate(length);
    211         CoderResult result = null;
    212         while (true) {
    213             result = decode(in, output, false);
    214             checkCoderResult(result);
    215             if (result.isUnderflow()) {
    216                 break;
    217             } else if (result.isOverflow()) {
    218                 output = allocateMore(output);
    219             }
    220         }
    221         result = decode(in, output, true);
    222         checkCoderResult(result);
    223 
    224         while (true) {
    225             result = flush(output);
    226             checkCoderResult(result);
    227             if (result.isOverflow()) {
    228                 output = allocateMore(output);
    229             } else {
    230                 break;
    231             }
    232         }
    233 
    234         output.flip();
    235         status = FLUSH;
    236         return output;
    237     }
    238 
    239     /*
    240      * checks the result whether it needs to throw CharacterCodingException.
    241      */
    242     private void checkCoderResult(CoderResult result)
    243             throws CharacterCodingException {
    244         if (result.isMalformed() && malformAction == CodingErrorAction.REPORT) {
    245             throw new MalformedInputException(result.length());
    246         } else if (result.isUnmappable()
    247                 && unmapAction == CodingErrorAction.REPORT) {
    248             throw new UnmappableCharacterException(result.length());
    249         }
    250     }
    251 
    252     /*
    253      * original output is full and doesn't have remaining. allocate more space
    254      * to new CharBuffer and return it, the contents in the given buffer will be
    255      * copied into the new buffer.
    256      */
    257     private CharBuffer allocateMore(CharBuffer output) {
    258         if (output.capacity() == 0) {
    259             return CharBuffer.allocate(1);
    260         }
    261         CharBuffer result = CharBuffer.allocate(output.capacity() * 2);
    262         output.flip();
    263         result.put(output);
    264         return result;
    265     }
    266 
    267     /**
    268      * Decodes bytes starting at the current position of the given input buffer,
    269      * and writes the equivalent character sequence into the given output buffer
    270      * from its current position.
    271      * <p>
    272      * The buffers' position will be changed with the reading and writing
    273      * operation, but their limits and marks will be kept intact.
    274      * <p>
    275      * A <code>CoderResult</code> instance will be returned according to
    276      * following rules:
    277      * <ul>
    278      * <li>{@link CoderResult#OVERFLOW CoderResult.OVERFLOW} indicates that
    279      * even though not all of the input has been processed, the buffer the
    280      * output is being written to has reached its capacity. In the event of this
    281      * code being returned this method should be called once more with an
    282      * <code>out</code> argument that has not already been filled.</li>
    283      * <li>{@link CoderResult#UNDERFLOW CoderResult.UNDERFLOW} indicates that
    284      * as many bytes as possible in the input buffer have been decoded. If there
    285      * is no further input and no remaining bytes in the input buffer then this
    286      * operation may be regarded as complete. Otherwise, this method should be
    287      * called once more with additional input.</li>
    288      * <li>A {@link CoderResult#malformedForLength(int) malformed input} result
    289      * indicates that some malformed input error has been encountered, and the
    290      * erroneous bytes start at the input buffer's position and their number can
    291      * be got by result's {@link CoderResult#length() length}. This kind of
    292      * result can be returned only if the malformed action is
    293      * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}. </li>
    294      * <li>A {@link CoderResult#unmappableForLength(int) unmappable character}
    295      * result indicates that some unmappable character error has been
    296      * encountered, and the erroneous bytes start at the input buffer's position
    297      * and their number can be got by result's
    298      * {@link CoderResult#length() length}. This kind of result can be returned
    299      * only if the unmappable character action is
    300      * {@link CodingErrorAction#REPORT CodingErrorAction.REPORT}. </li>
    301      * </ul>
    302      * <p>
    303      * The <code>endOfInput</code> parameter indicates that the invoker cannot
    304      * provide further input. This parameter is true if and only if the bytes in
    305      * current input buffer are all inputs for this decoding operation. Note
    306      * that it is common and won't cause an error if the invoker sets false and
    307      * then can't provide more input, while it may cause an error if the invoker
    308      * always sets true in several consecutive invocations. This would make the
    309      * remaining input to be treated as malformed input.
    310      * <p>
    311      * This method invokes the
    312      * {@link #decodeLoop(ByteBuffer, CharBuffer) decodeLoop} method to
    313      * implement the basic decode logic for a specific charset.
    314      *
    315      * @param in
    316      *            the input buffer.
    317      * @param out
    318      *            the output buffer.
    319      * @param endOfInput
    320      *            true if all the input characters have been provided.
    321      * @return a <code>CoderResult</code> instance which indicates the reason
    322      *         of termination.
    323      * @throws IllegalStateException
    324      *             if decoding has started or no more input is needed in this
    325      *             decoding progress.
    326      * @throws CoderMalfunctionError
    327      *             if the {@link #decodeLoop(ByteBuffer, CharBuffer) decodeLoop}
    328      *             method threw an <code>BufferUnderflowException</code> or
    329      *             <code>BufferOverflowException</code>.
    330      */
    331     public final CoderResult decode(ByteBuffer in, CharBuffer out,
    332             boolean endOfInput) {
    333         /*
    334          * status check
    335          */
    336         if ((status == FLUSH) || (!endOfInput && status == END)) {
    337             throw new IllegalStateException();
    338         }
    339 
    340         CoderResult result = null;
    341 
    342         // begin to decode
    343         while (true) {
    344             CodingErrorAction action = null;
    345             try {
    346                 result = decodeLoop(in, out);
    347             } catch (BufferOverflowException ex) {
    348                 // unexpected exception
    349                 throw new CoderMalfunctionError(ex);
    350             } catch (BufferUnderflowException ex) {
    351                 // unexpected exception
    352                 throw new CoderMalfunctionError(ex);
    353             }
    354 
    355             /*
    356              * result handling
    357              */
    358             if (result.isUnderflow()) {
    359                 int remaining = in.remaining();
    360                 status = endOfInput ? END : ONGOING;
    361                 if (endOfInput && remaining > 0) {
    362                     result = CoderResult.malformedForLength(remaining);
    363                 } else {
    364                     return result;
    365                 }
    366             }
    367             if (result.isOverflow()) {
    368                 return result;
    369             }
    370             // set coding error handle action
    371             action = malformAction;
    372             if (result.isUnmappable()) {
    373                 action = unmapAction;
    374             }
    375             // If the action is IGNORE or REPLACE, we should continue decoding.
    376             if (action == CodingErrorAction.REPLACE) {
    377                 if (out.remaining() < replace.length()) {
    378                     return CoderResult.OVERFLOW;
    379                 }
    380                 out.put(replace);
    381             } else {
    382                 if (action != CodingErrorAction.IGNORE)
    383                     return result;
    384             }
    385             in.position(in.position() + result.length());
    386         }
    387     }
    388 
    389     /**
    390      * Decodes bytes into characters. This method is called by the
    391      * {@link #decode(ByteBuffer, CharBuffer, boolean) decode} method.
    392      * <p>
    393      * This method will implement the essential decoding operation, and it won't
    394      * stop decoding until either all the input bytes are read, the output
    395      * buffer is filled, or some exception is encountered. Then it will return a
    396      * <code>CoderResult</code> object indicating the result of current
    397      * decoding operation. The rules to construct the <code>CoderResult</code>
    398      * are the same as for
    399      * {@link #decode(ByteBuffer, CharBuffer, boolean) decode}. When an
    400      * exception is encountered in the decoding operation, most implementations
    401      * of this method will return a relevant result object to the
    402      * {@link #decode(ByteBuffer, CharBuffer, boolean) decode} method, and some
    403      * performance optimized implementation may handle the exception and
    404      * implement the error action itself.
    405      * <p>
    406      * The buffers are scanned from their current positions, and their positions
    407      * will be modified accordingly, while their marks and limits will be
    408      * intact. At most {@link ByteBuffer#remaining() in.remaining()} characters
    409      * will be read, and {@link CharBuffer#remaining() out.remaining()} bytes
    410      * will be written.
    411      * <p>
    412      * Note that some implementations may pre-scan the input buffer and return a
    413      * <code>CoderResult.UNDERFLOW</code> until it receives sufficient input.
    414      *
    415      * @param in
    416      *            the input buffer.
    417      * @param out
    418      *            the output buffer.
    419      * @return a <code>CoderResult</code> instance indicating the result.
    420      */
    421     protected abstract CoderResult decodeLoop(ByteBuffer in, CharBuffer out);
    422 
    423     /**
    424      * Gets the charset detected by this decoder; this method is optional.
    425      * <p>
    426      * If implementing an auto-detecting charset, then this decoder returns the
    427      * detected charset from this method when it is available. The returned
    428      * charset will be the same for the rest of the decode operation.
    429      * <p>
    430      * If insufficient bytes have been read to determine the charset, an
    431      * <code>IllegalStateException</code> will be thrown.
    432      * <p>
    433      * The default implementation always throws
    434      * <code>UnsupportedOperationException</code>, so it should be overridden
    435      * by a subclass if needed.
    436      *
    437      * @return the charset detected by this decoder, or null if it is not yet
    438      *         determined.
    439      * @throws UnsupportedOperationException
    440      *             if this decoder does not implement an auto-detecting charset.
    441      * @throws IllegalStateException
    442      *             if insufficient bytes have been read to determine the
    443      *             charset.
    444      */
    445     public Charset detectedCharset() {
    446         throw new UnsupportedOperationException();
    447     }
    448 
    449     /**
    450      * Flushes this decoder.
    451      *
    452      * This method will call {@link #implFlush(CharBuffer) implFlush}. Some
    453      * decoders may need to write some characters to the output buffer when they
    454      * have read all input bytes; subclasses can override
    455      * {@link #implFlush(CharBuffer) implFlush} to perform the writing operation.
    456      * <p>
    457      * The maximum number of written bytes won't be larger than
    458      * {@link CharBuffer#remaining() out.remaining()}. If some decoder wants to
    459      * write more bytes than an output buffer's remaining space allows, then a
    460      * <code>CoderResult.OVERFLOW</code> will be returned, and this method
    461      * must be called again with a character buffer that has more remaining
    462      * space. Otherwise this method will return
    463      * <code>CoderResult.UNDERFLOW</code>, which means one decoding process
    464      * has been completed successfully.
    465      * <p>
    466      * During the flush, the output buffer's position will be changed
    467      * accordingly, while its mark and limit will be intact.
    468      *
    469      * @param out
    470      *            the given output buffer.
    471      * @return <code>CoderResult.UNDERFLOW</code> or
    472      *         <code>CoderResult.OVERFLOW</code>.
    473      * @throws IllegalStateException
    474      *             if this decoder hasn't read all input bytes during one
    475      *             decoding process, which means neither after calling
    476      *             {@link #decode(ByteBuffer) decode(ByteBuffer)} nor after
    477      *             calling {@link #decode(ByteBuffer, CharBuffer, boolean)
    478      *             decode(ByteBuffer, CharBuffer, boolean)} with true as value
    479      *             for the last boolean parameter.
    480      */
    481     public final CoderResult flush(CharBuffer out) {
    482         if (status != END && status != INIT) {
    483             throw new IllegalStateException();
    484         }
    485         CoderResult result = implFlush(out);
    486         if (result == CoderResult.UNDERFLOW) {
    487             status = FLUSH;
    488         }
    489         return result;
    490     }
    491 
    492     /**
    493      * Flushes this decoder. The default implementation does nothing and always
    494      * returns <code>CoderResult.UNDERFLOW</code>; this method can be
    495      * overridden if needed.
    496      *
    497      * @param out
    498      *            the output buffer.
    499      * @return <code>CoderResult.UNDERFLOW</code> or
    500      *         <code>CoderResult.OVERFLOW</code>.
    501      */
    502     protected CoderResult implFlush(CharBuffer out) {
    503         return CoderResult.UNDERFLOW;
    504     }
    505 
    506     /**
    507      * Notifies that this decoder's <code>CodingErrorAction</code> specified
    508      * for malformed input error has been changed. The default implementation
    509      * does nothing; this method can be overridden if needed.
    510      *
    511      * @param newAction
    512      *            the new action.
    513      */
    514     protected void implOnMalformedInput(CodingErrorAction newAction) {
    515         // default implementation is empty
    516     }
    517 
    518     /**
    519      * Notifies that this decoder's <code>CodingErrorAction</code> specified
    520      * for unmappable character error has been changed. The default
    521      * implementation does nothing; this method can be overridden if needed.
    522      *
    523      * @param newAction
    524      *            the new action.
    525      */
    526     protected void implOnUnmappableCharacter(CodingErrorAction newAction) {
    527         // default implementation is empty
    528     }
    529 
    530     /**
    531      * Notifies that this decoder's replacement has been changed. The default
    532      * implementation does nothing; this method can be overridden if needed.
    533      *
    534      * @param newReplacement
    535      *            the new replacement string.
    536      */
    537     protected void implReplaceWith(String newReplacement) {
    538         // default implementation is empty
    539     }
    540 
    541     /**
    542      * Reset this decoder's charset related state. The default implementation
    543      * does nothing; this method can be overridden if needed.
    544      */
    545     protected void implReset() {
    546         // default implementation is empty
    547     }
    548 
    549     /**
    550      * Indicates whether this decoder implements an auto-detecting charset.
    551      *
    552      * @return <code>true</code> if this decoder implements an auto-detecting
    553      *         charset.
    554      */
    555     public boolean isAutoDetecting() {
    556         return false;
    557     }
    558 
    559     /**
    560      * Indicates whether this decoder has detected a charset; this method is
    561      * optional.
    562      * <p>
    563      * If this decoder implements an auto-detecting charset, then this method
    564      * may start to return true during decoding operation to indicate that a
    565      * charset has been detected in the input bytes and that the charset can be
    566      * retrieved by invoking the {@link #detectedCharset() detectedCharset}
    567      * method.
    568      * <p>
    569      * Note that a decoder that implements an auto-detecting charset may still
    570      * succeed in decoding a portion of the given input even when it is unable
    571      * to detect the charset. For this reason users should be aware that a
    572      * <code>false</code> return value does not indicate that no decoding took
    573      * place.
    574      * <p>
    575      * The default implementation always throws an
    576      * <code>UnsupportedOperationException</code>; it should be overridden by
    577      * a subclass if needed.
    578      *
    579      * @return <code>true</code> if this decoder has detected a charset.
    580      * @throws UnsupportedOperationException
    581      *             if this decoder doesn't implement an auto-detecting charset.
    582      */
    583     public boolean isCharsetDetected() {
    584         throw new UnsupportedOperationException();
    585     }
    586 
    587     /**
    588      * Gets this decoder's <code>CodingErrorAction</code> when malformed input
    589      * occurred during the decoding process.
    590      *
    591      * @return this decoder's <code>CodingErrorAction</code> when malformed
    592      *         input occurred during the decoding process.
    593      */
    594     public CodingErrorAction malformedInputAction() {
    595         return malformAction;
    596     }
    597 
    598     /**
    599      * Gets the maximum number of characters which can be created by this
    600      * decoder for one input byte, must be positive.
    601      *
    602      * @return the maximum number of characters which can be created by this
    603      *         decoder for one input byte, must be positive.
    604      */
    605     public final float maxCharsPerByte() {
    606         return maxChars;
    607     }
    608 
    609     /**
    610      * Sets this decoder's action on malformed input errors.
    611      *
    612      * This method will call the
    613      * {@link #implOnMalformedInput(CodingErrorAction) implOnMalformedInput}
    614      * method with the given new action as argument.
    615      *
    616      * @param newAction
    617      *            the new action on malformed input error.
    618      * @return this decoder.
    619      * @throws IllegalArgumentException
    620      *             if {@code newAction} is {@code null}.
    621      */
    622     public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
    623         if (null == newAction) {
    624             throw new IllegalArgumentException();
    625         }
    626         malformAction = newAction;
    627         implOnMalformedInput(newAction);
    628         return this;
    629     }
    630 
    631     /**
    632      * Sets this decoder's action on unmappable character errors.
    633      *
    634      * This method will call the
    635      * {@link #implOnUnmappableCharacter(CodingErrorAction) implOnUnmappableCharacter}
    636      * method with the given new action as argument.
    637      *
    638      * @param newAction
    639      *            the new action on unmappable character error.
    640      * @return this decoder.
    641      * @throws IllegalArgumentException
    642      *             if {@code newAction} is {@code null}.
    643      */
    644     public final CharsetDecoder onUnmappableCharacter(
    645             CodingErrorAction newAction) {
    646         if (null == newAction) {
    647             throw new IllegalArgumentException();
    648         }
    649         unmapAction = newAction;
    650         implOnUnmappableCharacter(newAction);
    651         return this;
    652     }
    653 
    654     /**
    655      * Gets the replacement string, which is never null or empty.
    656      *
    657      * @return the replacement string, cannot be null or empty.
    658      */
    659     public final String replacement() {
    660         return replace;
    661     }
    662 
    663     /**
    664      * Sets the new replacement string.
    665      *
    666      * This method first checks the given replacement's validity, then changes
    667      * the replacement value, and at last calls the
    668      * {@link #implReplaceWith(String) implReplaceWith} method with the given
    669      * new replacement as argument.
    670      *
    671      * @param newReplacement
    672      *            the replacement string, cannot be null or empty. Its length
    673      *            cannot be larger than {@link #maxCharsPerByte()}.
    674      * @return this decoder.
    675      * @throws IllegalArgumentException
    676      *             if the given replacement cannot satisfy the requirement
    677      *             mentioned above.
    678      */
    679     public final CharsetDecoder replaceWith(String newReplacement) {
    680         if (newReplacement == null || newReplacement.isEmpty()) {
    681             throw new IllegalArgumentException("Replacement string cannot be null or empty");
    682         }
    683         if (newReplacement.length() > maxChars) {
    684             throw new IllegalArgumentException("Replacement string cannot be longer than max characters per byte");
    685         }
    686         replace = newReplacement;
    687         implReplaceWith(newReplacement);
    688         return this;
    689     }
    690 
    691     /**
    692      * Resets this decoder. This method will reset the internal status, and then
    693      * calls <code>implReset()</code> to reset any status related to the
    694      * specific charset.
    695      *
    696      * @return this decoder.
    697      */
    698     public final CharsetDecoder reset() {
    699         status = INIT;
    700         implReset();
    701         return this;
    702     }
    703 
    704     /**
    705      * Gets this decoder's <code>CodingErrorAction</code> when an unmappable
    706      * character error occurred during the decoding process.
    707      *
    708      * @return this decoder's <code>CodingErrorAction</code> when an
    709      *         unmappable character error occurred during the decoding process.
    710      */
    711     public CodingErrorAction unmappableCharacterAction() {
    712         return unmapAction;
    713     }
    714 }
    715