All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.util.json.JSONBuffer Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2016-2022 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2016-2022 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2016-2022 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.util.json;



import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.LinkedList;

import com.unboundid.util.ByteStringBuffer;
import com.unboundid.util.Mutable;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;



/**
 * This class provides a mechanism for constructing the string representation of
 * one or more JSON objects by appending elements of those objects into a byte
 * string buffer.  {@code JSONBuffer} instances may be cleared and reused any
 * number of times.  They are not threadsafe and should not be accessed
 * concurrently by multiple threads.
 * 

* Note that the caller is responsible for proper usage to ensure that the * buffer results in a valid JSON encoding. This includes ensuring that the * object begins with the appropriate opening curly brace, that all objects * and arrays are properly closed, that raw values are not used outside of * arrays, that named fields are not added into arrays, etc. */ @Mutable() @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) public final class JSONBuffer implements Serializable { /** * The default maximum buffer size. */ private static final int DEFAULT_MAX_BUFFER_SIZE = 1_048_576; /** * The serial version UID for this serializable class. */ private static final long serialVersionUID = 5946166401452532693L; // Indicates whether to format the JSON object across multiple lines rather // than putting it all on a single line. private final boolean multiLine; // Indicates whether we need to add a comma before adding the next element. private boolean needComma = false; // The buffer to which all data will be written. @NotNull private ByteStringBuffer buffer; // The maximum buffer size that should be retained. private final int maxBufferSize; // A list of the indents that we need to use when formatting multi-line // objects. @NotNull private final LinkedList indents; /** * Creates a new instance of this JSON buffer with the default maximum buffer * size. */ public JSONBuffer() { this(DEFAULT_MAX_BUFFER_SIZE); } /** * Creates a new instance of this JSON buffer with an optional maximum * retained size. If a maximum size is defined, then this buffer may be used * to hold elements larger than that, but when the buffer is cleared it will * be shrunk to the maximum size. * * @param maxBufferSize The maximum buffer size that will be retained by * this JSON buffer. A value less than or equal to * zero indicates that no maximum size should be * enforced. */ public JSONBuffer(final int maxBufferSize) { this(null, maxBufferSize, false); } /** * Creates a new instance of this JSON buffer that wraps the provided byte * string buffer (if provided) and that has an optional maximum retained size. * If a maximum size is defined, then this buffer may be used to hold elements * larger than that, but when the buffer is cleared it will be shrunk to the * maximum size. * * @param buffer The buffer to wrap. It may be {@code null} if a new * buffer should be created. * @param maxBufferSize The maximum buffer size that will be retained by * this JSON buffer. A value less than or equal to * zero indicates that no maximum size should be * enforced. * @param multiLine Indicates whether to format JSON objects using a * user-friendly, formatted, multi-line representation * rather than constructing the entire element without * any line breaks. Note that regardless of the value * of this argument, there will not be an end-of-line * marker at the very end of the object. */ public JSONBuffer(@Nullable final ByteStringBuffer buffer, final int maxBufferSize, final boolean multiLine) { this.multiLine = multiLine; this.maxBufferSize = maxBufferSize; indents = new LinkedList<>(); needComma = false; if (buffer == null) { this.buffer = new ByteStringBuffer(); } else { this.buffer = buffer; } } /** * Clears the contents of this buffer. */ public void clear() { buffer.clear(); if ((maxBufferSize > 0) && (buffer.capacity() > maxBufferSize)) { buffer.setCapacity(maxBufferSize); } needComma = false; indents.clear(); } /** * Replaces the underlying buffer to which the JSON object data will be * written. * * @param buffer The underlying buffer to which the JSON object data will be * written. */ public void setBuffer(@Nullable final ByteStringBuffer buffer) { if (buffer == null) { this.buffer = new ByteStringBuffer(); } else { this.buffer = buffer; } needComma = false; indents.clear(); } /** * Retrieves the current length of this buffer in bytes. * * @return The current length of this buffer in bytes. */ public int length() { return buffer.length(); } /** * Appends the open curly brace needed to signify the beginning of a JSON * object. This will not include a field name, so it should only be used to * start the outermost JSON object, or to start a JSON object contained in an * array. */ public void beginObject() { addComma(); buffer.append("{ "); needComma = false; addIndent(2); } /** * Begins a new JSON object that will be used as the value of the specified * field. * * @param fieldName The name of the field */ public void beginObject(@NotNull final String fieldName) { addComma(); final int startPos = buffer.length(); JSONString.encodeString(fieldName, buffer); final int fieldNameLength = buffer.length() - startPos; buffer.append(":{ "); needComma = false; addIndent(fieldNameLength + 3); } /** * Appends the close curly brace needed to signify the end of a JSON object. */ public void endObject() { if (needComma) { buffer.append(' '); } buffer.append('}'); needComma = true; removeIndent(); } /** * Appends the open curly brace needed to signify the beginning of a JSON * array. This will not include a field name, so it should only be used to * start a JSON array contained in an array. */ public void beginArray() { addComma(); buffer.append("[ "); needComma = false; addIndent(2); } /** * Begins a new JSON array that will be used as the value of the specified * field. * * @param fieldName The name of the field */ public void beginArray(@NotNull final String fieldName) { addComma(); final int startPos = buffer.length(); JSONString.encodeString(fieldName, buffer); final int fieldNameLength = buffer.length() - startPos; buffer.append(":[ "); needComma = false; addIndent(fieldNameLength + 3); } /** * Appends the close square bracket needed to signify the end of a JSON array. */ public void endArray() { if (needComma) { buffer.append(' '); } buffer.append(']'); needComma = true; removeIndent(); } /** * Appends the provided Boolean value. This will not include a field name, so * it should only be used for Boolean value elements in an array. * * @param value The Boolean value to append. */ public void appendBoolean(final boolean value) { addComma(); if (value) { buffer.append("true"); } else { buffer.append("false"); } needComma = true; } /** * Appends a JSON field with the specified name and the provided Boolean * value. * * @param fieldName The name of the field. * @param value The Boolean value. */ public void appendBoolean(@NotNull final String fieldName, final boolean value) { addComma(); JSONString.encodeString(fieldName, buffer); if (value) { buffer.append(":true"); } else { buffer.append(":false"); } needComma = true; } /** * Appends the provided JSON null value. This will not include a field name, * so it should only be used for null value elements in an array. */ public void appendNull() { addComma(); buffer.append("null"); needComma = true; } /** * Appends a JSON field with the specified name and a null value. * * @param fieldName The name of the field. */ public void appendNull(@NotNull final String fieldName) { addComma(); JSONString.encodeString(fieldName, buffer); buffer.append(":null"); needComma = true; } /** * Appends the provided JSON number value. This will not include a field * name, so it should only be used for number elements in an array. * * @param value The number to add. */ public void appendNumber(@NotNull final BigDecimal value) { addComma(); buffer.append(value.toPlainString()); needComma = true; } /** * Appends the provided JSON number value. This will not include a field * name, so it should only be used for number elements in an array. * * @param value The number to add. */ public void appendNumber(final int value) { addComma(); buffer.append(value); needComma = true; } /** * Appends the provided JSON number value. This will not include a field * name, so it should only be used for number elements in an array. * * @param value The number to add. */ public void appendNumber(final long value) { addComma(); buffer.append(value); needComma = true; } /** * Appends the provided JSON number value. This will not include a field * name, so it should only be used for number elements in an array. * * @param value The string representation of the number to add. It must be * properly formed. */ public void appendNumber(@NotNull final String value) { addComma(); buffer.append(value); needComma = true; } /** * Appends a JSON field with the specified name and a number value. * * @param fieldName The name of the field. * @param value The number value. */ public void appendNumber(@NotNull final String fieldName, @NotNull final BigDecimal value) { addComma(); JSONString.encodeString(fieldName, buffer); buffer.append(':'); buffer.append(value.toPlainString()); needComma = true; } /** * Appends a JSON field with the specified name and a number value. * * @param fieldName The name of the field. * @param value The number value. */ public void appendNumber(@NotNull final String fieldName, final int value) { addComma(); JSONString.encodeString(fieldName, buffer); buffer.append(':'); buffer.append(value); needComma = true; } /** * Appends a JSON field with the specified name and a number value. * * @param fieldName The name of the field. * @param value The number value. */ public void appendNumber(@NotNull final String fieldName, final long value) { addComma(); JSONString.encodeString(fieldName, buffer); buffer.append(':'); buffer.append(value); needComma = true; } /** * Appends a JSON field with the specified name and a number value. * * @param fieldName The name of the field. * @param value The string representation of the number ot add. It must * be properly formed. */ public void appendNumber(@NotNull final String fieldName, @NotNull final String value) { addComma(); JSONString.encodeString(fieldName, buffer); buffer.append(':'); buffer.append(value); needComma = true; } /** * Appends the provided JSON string value. This will not include a field * name, so it should only be used for string elements in an array. * * @param value The value to add. */ public void appendString(@NotNull final String value) { addComma(); JSONString.encodeString(value, buffer); needComma = true; } /** * Appends a JSON field with the specified name and a null value. * * @param fieldName The name of the field. * @param value The value to add. */ public void appendString(@NotNull final String fieldName, @NotNull final String value) { addComma(); JSONString.encodeString(fieldName, buffer); buffer.append(':'); JSONString.encodeString(value, buffer); needComma = true; } /** * Appends the provided JSON value. This will not include a field name, so it * should only be used for elements in an array. * * @param value The value to append. */ public void appendValue(@NotNull final JSONValue value) { value.appendToJSONBuffer(this); } /** * Appends the provided JSON value. This will not include a field name, so it * should only be used for elements in an array. * * @param fieldName The name of the field. * @param value The value to append. */ public void appendValue(@NotNull final String fieldName, @NotNull final JSONValue value) { value.appendToJSONBuffer(fieldName, this); } /** * Retrieves the byte string buffer that backs this JSON buffer. * * @return The byte string buffer that backs this JSON buffer. */ @NotNull() public ByteStringBuffer getBuffer() { return buffer; } /** * Writes the current contents of this JSON buffer to the provided output * stream. Note that based on the current contents of this buffer and the way * it has been used so far, it may not represent a valid JSON object. * * @param outputStream The output stream to which the current contents of * this JSON buffer should be written. * * @throws IOException If a problem is encountered while writing to the * provided output stream. */ public void writeTo(@NotNull final OutputStream outputStream) throws IOException { buffer.write(outputStream); } /** * Retrieves a string representation of the current contents of this JSON * buffer. Note that based on the current contents of this buffer and the way * it has been used so far, it may not represent a valid JSON object. * * @return A string representation of the current contents of this JSON * buffer. */ @Override() @NotNull() public String toString() { return buffer.toString(); } /** * Retrieves the current contents of this JSON buffer as a JSON object. * * @return The JSON object decoded from the contents of this JSON buffer. * * @throws JSONException If the buffer does not currently contain exactly * one valid JSON object. */ @NotNull() public JSONObject toJSONObject() throws JSONException { return new JSONObject(buffer.toString()); } /** * Adds a comma and line break to the buffer if appropriate. */ private void addComma() { if (needComma) { buffer.append(','); if (multiLine) { buffer.append(StaticUtils.EOL_BYTES); buffer.append(indents.getLast()); } else { buffer.append(' '); } } } /** * Adds an indent to the set of indents of appropriate. * * @param size The number of spaces to indent. */ private void addIndent(final int size) { if (multiLine) { final char[] spaces = new char[size]; Arrays.fill(spaces, ' '); final String indentStr = new String(spaces); if (indents.isEmpty()) { indents.add(indentStr); } else { indents.add(indents.getLast() + indentStr); } } } /** * Removes an indent from the set of indents of appropriate. */ private void removeIndent() { if (multiLine && (! indents.isEmpty())) { indents.removeLast(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy