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