StringBuilderWriter.java

/*
 * Copyright (c) 2026 Contributors to the Eclipse Foundation. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
package org.glassfish.jaxb.runtime.util;

import java.io.IOException;
import java.io.Writer;

/**
 * A character stream that collects its output in a string builder, which can
 * then be used to construct a string.
 *
 * <p>
 * Closing a {@code StringBuilderWriter} has no effect. The methods in this class
 * can be called after the stream has been closed without generating an
 * {@code IOException}.
 *
 * <p>This class is an alternative of JDK {@code java.io.StringWriter}.
 * It is backed up by {@link StringBuilder} for better performance without the
 * need of synchronization of a {@link StringBuffer}.
 *
 * <p>Instances of {@code StringBuilderWriter} are not safe for
 * use by multiple threads. If such synchronization is required then it is
 * recommended that {@link java.io.StringWriter} be used.
 *
 * @author      Laurent Schoelens
 * @since       4.0.7
 */
public class StringBuilderWriter extends Writer {

    private final StringBuilder sb;

    /**
     * Create a new string-builder writer using the default initial string-builder size.
     */
    public StringBuilderWriter() {
        this(null);
    }

    /**
     * Create a new string-builder writer using the specified initial string-builder size.
     *
     * @param initialSize
     *        The number of {@code char} values that will fit into this StringBuilder
     *        before it is automatically expanded
     *
     * @throws IllegalArgumentException
     *         If {@code initialSize} is negative
     */
    public StringBuilderWriter(int initialSize) {
        if (initialSize < 0) {
            throw new IllegalArgumentException("Negative buffer size");
        }
        this.sb = new StringBuilder(initialSize);
    }

    /**
     * Create a new string-builder writer using the specified string-builder.
     *
     * @param sb
     *        The string-builder to use. could be null and default-sized
     *        string-builder will be created
     */
    public StringBuilderWriter(StringBuilder sb) {
        this.sb = sb == null ? new StringBuilder() : sb;
    }

    /**
     * Return the string builder itself.
     *
     * @return StringBuilder holding the current string-builder value.
     */
    public StringBuilder getBuilder() {
        return sb;
    }

    /**
     * Writes a single character.
     *
     * @param c
     *         int specifying a character to be written
     *
     * @throws IOException
     *          If an I/O error occurs
     */
    @Override
    public void write(int c) throws IOException {
        sb.append(c);
    }

    /**
     * Writes an array of characters.
     *
     * @param cbuf
     *         Array of characters to be written
     *
     * @throws IOException
     *          If an I/O error occurs
     */
    @Override
    public void write(char[] cbuf) throws IOException {
        sb.append(cbuf);
    }

    /**
     * Writes a portion of an array of characters.
     *
     * @param cbuf
     *         Array of characters
     * @param off
     *         Offset from which to start writing characters
     * @param len
     *         Number of characters to write
     *
     * @throws IOException
     *          If an I/O error occurs
     */
    @Override
    public void write(char[] cbuf, int off, int len) throws IOException {
        sb.append(cbuf, off, len);
    }

    /**
     * Writes a string.
     *
     * @param str
     *         String to be written
     *
     * @throws IOException
     *          If an I/O error occurs
     */
    @Override
    public void write(String str) throws IOException {
        sb.append(str);
    }

    /**
     * Writes a portion of a string.
     *
     * @param str
     *         A String
     * @param off
     *         Offset from which to start writing characters
     * @param len
     *         Number of characters to write
     *
     * @throws IOException
     *          If an I/O error occurs
     */
    @Override
    public void write(String str, int off, int len) throws IOException {
        sb.append(str, off, len);
    }

    /**
     * Appends the specified character sequence to this writer.
     *
     * @param csq
     *         The character sequence to append.  If {@code csq} is
     *         {@code null}, then the four characters {@code "null"} are
     *         appended to this writer.
     *
     * @return This writer
     * @throws IOException
     *          If an I/O error occurs
     */
    @Override
    public Writer append(CharSequence csq) throws IOException {
        sb.append(csq);
        return this;
    }

    /**
     * Return the buffer's current value as a string.
     */
    public String toString() {
        return sb.toString();
    }

    /**
     * Flush the stream.
     *
     * <p> The {@code flush} method of {@code StringBuilderWriter} does nothing.
     */
    @Override
    public void flush() {
        // no-op
    }

    /**
     * Closing a {@code StringBuilderWriter} has no effect. The methods in this
     * class can be called after the stream has been closed without generating
     * an {@code IOException}.
     */
    @Override
    public void close() {
        // no-op
    }
}