com.amazon.ion.system.IonTextWriterBuilder Maven / Gradle / Ivy
Show all versions of ion-java Show documentation
/*
* Copyright 2007-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/
package com.amazon.ion.system;
import static com.amazon.ion.system.IonWriterBuilder.InitialIvmHandling.SUPPRESS;
import com.amazon.ion.IonCatalog;
import com.amazon.ion.IonWriter;
import com.amazon.ion.SymbolTable;
import com.amazon.ion.Timestamp;
import com.amazon.ion.impl._Private_IonTextWriterBuilder;
import com.amazon.ion.impl._Private_Utils;
import java.io.OutputStream;
import java.nio.charset.Charset;
/**
* The builder for creating {@link IonWriter}s emitting the Ion text syntax.
*
* WARNING: This class should not be extended by code outside of
* this library.
*
* Builders may be configured once and reused to construct multiple
* objects.
*
* Instances of this class are not not safe for use by multiple threads
* unless they are {@linkplain #immutable() immutable}.
*
* The most general and correct approach is to use the {@link #standard()}
* builder:
*
* IonWriter w = IonTextWriterBuilder.standard().build(outputStream);
*
* The standard configuration gives a direct representation of what's written,
* including version markers and local symbol tables. That's good for
* diagnostics but it may be more than you want in many situations.
* In such cases the {@link #minimal()} or {@link #pretty()} builders (or a
* combination) may give more satisfying output:
*
* IonWriter w = IonTextWriterBuilder.minimal()
* .withPrettyPrinting()
* .build(outputStream);
*
*
*
* Configuration properties follow the standard JavaBeans idiom in order to be
* friendly to dependency injection systems. They also provide alternative
* {@code with...()} mutation methods that enable a more fluid style.
*
*
Auto-flushing
*
* {@link IonWriter}s created by this builder auto-flush to the
* underlying data sink after writing each top-level value in the context of
* the writer.
*
* Currently, there is no configuration point available to disable the
* auto-flushing mechanism. Please vote on
* issue amazon-ion/ion-java/issues/32
* if you require it.
*
*/
public abstract class IonTextWriterBuilder
extends IonWriterBuilderBase
{
/**
* A strategy for minimizing the output of local symbol tables.
* By default, no minimization takes place and the writer outputs all data
* as-is.
*
*/
public enum LstMinimizing
{
/**
* Discards local symbols, retains imports.
*/
LOCALS,
/* TODO Discards local symbols and imports, retains open content.
* This isn't implemented yet, because our symtab implmentations don't
* support open content (so it would work the same as EVERYTHING).
*/
// IMPORTS,
/**
* Discards everything, collapsing the LST to an IVM.
* If {@link com.amazon.ion.system.IonWriterBuilder.IvmMinimizing}
* is also in effect, then even that IVM may be suppressed.
*
* @see IonTextWriterBuilder#setIvmMinimizing(IonWriterBuilder.IvmMinimizing)
*/
EVERYTHING
}
/**
* The {@code "US-ASCII"} charset.
*/
public static final Charset ASCII = _Private_Utils.ASCII_CHARSET;
/**
* The {@code "UTF-8"} charset.
*/
public static final Charset UTF8 = _Private_Utils.UTF8_CHARSET;
/**
* Represents common new-line separators that are valid in Ion.
*
* Unicode defines several characters that can represent a new line, but only carriage return (CR) and linefeed (LF) are valid whitespace in Ion.
* Using other new-line characters (such as {@code NEL}) will result in printing invalid Ion.
*/
public enum NewLineType {
/**
* A carriage return and linefeed ({@code U+000D} followed by {@code U+000A}).
*/
CRLF("\r\n"),
/**
* A single linefeed ({@code U+000A}).
*/
LF("\n"),
/**
* The new-line separator specified in the "line.separator" system property.
* Using this will result in writing invalid Ion if the platform uses anything other than CR and/or LF as the line separator
* and the IonTextWriter is configured to use pretty printing or to write each top-level value on a separate line.
*/
PLATFORM_DEPENDENT(System.getProperty("line.separator"));
private final CharSequence charSequence;
NewLineType(CharSequence cs) {
this.charSequence = cs;
}
public CharSequence getCharSequence() {
return charSequence;
}
}
/**
* The standard builder of text {@link IonWriter}s, with all configuration
* properties having their default values. The resulting output is a
* direct representation of what's written to the writer, including
* version markers and local symbol tables.
*
* @return a new, mutable builder instance.
*
* @see #minimal()
* @see #pretty()
* @see #json()
*/
public static IonTextWriterBuilder standard()
{
return _Private_IonTextWriterBuilder.standard();
}
/**
* Creates a builder configured to minimize system data, eliminating local
* symbol tables and minimizing version markers.
*
* @return a new, mutable builder instance.
*
* @see #withMinimalSystemData()
*
*/
public static IonTextWriterBuilder minimal()
{
return standard().withMinimalSystemData();
}
/**
* Creates a builder preconfigured for basic pretty-printing.
*
* The specifics of this configuration may change between releases of this
* library, so automated processes should not depend on the exact output
* formatting. In particular, there's currently no promise regarding
* handling of system data.
*
* @return a new, mutable builder instance.
*
* @see #withPrettyPrinting()
*/
public static IonTextWriterBuilder pretty()
{
return standard().withPrettyPrinting();
}
/**
* Creates a builder preconfigured for JSON compatibility.
*
* @return a new, mutable builder instance.
*
* @see #withJsonDowngrade()
*/
public static IonTextWriterBuilder json()
{
return standard().withJsonDowngrade();
}
//=========================================================================
// Config points:
// * Default IVM
// * Re-use same imports after a finish
// * Indentation CharSeq
private Charset myCharset;
private InitialIvmHandling myInitialIvmHandling;
private IvmMinimizing myIvmMinimizing;
private LstMinimizing myLstMinimizing;
private int myLongStringThreshold;
private NewLineType myNewLineType;
private boolean myTopLevelValuesOnNewLines;
private int myMaximumTimestampPrecisionDigits = Timestamp.DEFAULT_MAXIMUM_DIGITS_TEXT;
/** NOT FOR APPLICATION USE! */
protected IonTextWriterBuilder()
{
}
/** NOT FOR APPLICATION USE! */
protected IonTextWriterBuilder(IonTextWriterBuilder that)
{
super(that);
this.myCharset = that.myCharset;
this.myInitialIvmHandling = that.myInitialIvmHandling;
this.myIvmMinimizing = that.myIvmMinimizing;
this.myLstMinimizing = that.myLstMinimizing;
this.myLongStringThreshold = that.myLongStringThreshold;
this.myNewLineType = that.myNewLineType;
this.myTopLevelValuesOnNewLines = that.myTopLevelValuesOnNewLines;
this.myMaximumTimestampPrecisionDigits = that.myMaximumTimestampPrecisionDigits;
}
//=========================================================================
// Overrides to fix the return type in JavaDocs
@Override
public abstract IonTextWriterBuilder copy();
@Override
public abstract IonTextWriterBuilder immutable();
@Override
public abstract IonTextWriterBuilder mutable();
@Override
public final IonTextWriterBuilder withCatalog(IonCatalog catalog)
{
return super.withCatalog(catalog);
}
@Override
public final IonTextWriterBuilder withImports(SymbolTable... imports)
{
return super.withImports(imports);
}
//-------------------------------------------------------------------------
/**
* Gets the charset denoting the output encoding.
* Only ASCII and UTF-8 are supported.
*
* @return may be null, denoting the default of UTF-8.
*
* @see #setCharset(Charset)
* @see #withCharset(Charset)
*/
public final Charset getCharset()
{
return myCharset;
}
/**
* Sets the charset denoting the output encoding.
* Only ASCII and UTF-8 are supported; applications can use the helper
* constants {@link #ASCII} and {@link #UTF8}.
*
* @param charset may be null, denoting the default of UTF-8.
*
* @see #getCharset()
* @see #withCharset(Charset)
*
* @throws UnsupportedOperationException if this is immutable.
*/
public void setCharset(Charset charset)
{
mutationCheck();
if (charset == null
|| charset.equals(ASCII)
|| charset.equals(UTF8))
{
myCharset = charset;
}
else
{
throw new IllegalArgumentException("Unsupported Charset "
+ charset);
}
}
/**
* Declares the charset denoting the output encoding,
* returning a new mutable builder if this is immutable.
* Only ASCII and UTF-8 are supported; applications can use the helper
* constants {@link #ASCII} and {@link #UTF8}.
*
* @param charset may be null, denoting the default of UTF-8.
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*
* @see #getCharset()
* @see #setCharset(Charset)
*/
public final IonTextWriterBuilder withCharset(Charset charset)
{
IonTextWriterBuilder b = mutable();
b.setCharset(charset);
return b;
}
/**
* Declares the output encoding to be {@code US-ASCII}.
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*/
public final IonTextWriterBuilder withCharsetAscii()
{
return withCharset(ASCII);
}
//-------------------------------------------------------------------------
/**
* Declares that this builder should minimize system-level output
* (Ion version markers and local symbol tables).
*
* This is equivalent to:
*
* - {@link #setInitialIvmHandling(IonWriterBuilder.InitialIvmHandling)
* setInitialIvmHandling}{@code (}{@link IonWriterBuilder.InitialIvmHandling#SUPPRESS SUPPRESS}{@code )}
*
- {@link #setIvmMinimizing(IonWriterBuilder.IvmMinimizing)
* setIvmMinimizing}{@code (}{@link IonWriterBuilder.IvmMinimizing#DISTANT DISTANT}{@code )}
*
- {@link #setLstMinimizing(LstMinimizing)
* setLstMinimizing}{@code (}{@link LstMinimizing#EVERYTHING EVERYTHING}{@code )}
*
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*
*/
public final IonTextWriterBuilder withMinimalSystemData()
{
IonTextWriterBuilder b = mutable();
b.setInitialIvmHandling(SUPPRESS);
b.setIvmMinimizing(IvmMinimizing.DISTANT);
b.setLstMinimizing(LstMinimizing.EVERYTHING);
return b;
}
/**
* Declares that this builder should use basic pretty-printing.
* Does not alter the handling of system data.
* Calling this method alters several other configuration properties,
* so code should call it first, then make any necessary overrides.
*
* The specifics of this configuration may change between releases of this
* library, so automated processes should not depend on the exact output
* formatting.
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*/
public abstract IonTextWriterBuilder withPrettyPrinting();
/**
* Declares that this builder should downgrade the writers' output to
* JSON compatibility. This format cannot round-trip back to Ion with full
* fidelity.
*
* The specific conversions are as follows:
*
* - System data is suppressed per {@link #withMinimalSystemData()}.
*
- All annotations are suppressed.
*
- Nulls of any type are printed as JSON {@code null}.
*
- Blobs are printed as strings, containing Base64.
*
- Clobs are printed as strings, containing only Unicode code points
* U+00 through U+FF.
*
- Sexps are printed as lists.
*
- Symbols are printed as strings.
*
- Timestamps are printed as strings, using Ion timestamp format.
*
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*/
public abstract IonTextWriterBuilder withJsonDowngrade();
//-------------------------------------------------------------------------
/**
* {@inheritDoc}
*
* @return the initial IVM strategy.
* The default value ({@code null}) indicates that an initial IVM is
* emitted if and only if it is received by the writer.
*
* @see #setInitialIvmHandling(IonWriterBuilder.InitialIvmHandling)
* @see #withInitialIvmHandling(IonWriterBuilder.InitialIvmHandling)
*/
@Override
public final InitialIvmHandling getInitialIvmHandling()
{
return myInitialIvmHandling;
}
/**
* Sets the strategy for emitting Ion version markers at the start
* of the stream. By default, IVMs are emitted only when explicitly
* written or when necessary (for example, before data that's not Ion 1.0).
*
* @param handling the initial IVM strategy.
* Null indicates that explicitly-written IVMs will be emitted.
*
* @see #getInitialIvmHandling()
* @see #withInitialIvmHandling(IonWriterBuilder.InitialIvmHandling)
*
* @throws UnsupportedOperationException if this is immutable.
*/
public void setInitialIvmHandling(InitialIvmHandling handling)
{
mutationCheck();
myInitialIvmHandling = handling;
}
/**
* Declares the strategy for emitting Ion version markers at the start
* of the stream, returning a new mutable builder if this is immutable.
* By default, IVMs are emitted only when explicitly
* written or when necessary (for example, before data that's not Ion 1.0).
*
* @param handling the initial IVM strategy.
* Null indicates that explicitly-written IVMs will be emitted.
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*
* @see #setInitialIvmHandling(IonWriterBuilder.InitialIvmHandling)
* @see #withInitialIvmHandling(IonWriterBuilder.InitialIvmHandling)
*/
public final IonTextWriterBuilder
withInitialIvmHandling(InitialIvmHandling handling)
{
IonTextWriterBuilder b = mutable();
b.setInitialIvmHandling(handling);
return b;
}
//-------------------------------------------------------------------------
/**
* {@inheritDoc}
*
* @return the IVM minimizing strategy.
* The default value ({@code null}) indicates that no minimization occurs
* and IVMs are emitted as received by the writer.
*
* @see #setIvmMinimizing(IonWriterBuilder.IvmMinimizing)
* @see #withIvmMinimizing(IonWriterBuilder.IvmMinimizing)
*
*/
@Override
public final IvmMinimizing getIvmMinimizing()
{
return myIvmMinimizing;
}
/**
* Sets the strategy for reducing or eliminating non-initial Ion version
* markers. When null, IVMs are emitted as they are written.
*
* @param minimizing the IVM minimization strategy.
* Null indicates that all explicitly-written IVMs will be emitted.
*
* @see #getIvmMinimizing()
* @see #withIvmMinimizing(IonWriterBuilder.IvmMinimizing)
*
* @throws UnsupportedOperationException if this is immutable.
*
*/
public void setIvmMinimizing(IvmMinimizing minimizing)
{
mutationCheck();
myIvmMinimizing = minimizing;
}
/**
* Declares the strategy for reducing or eliminating non-initial Ion version
* markers, returning a new mutable builder if this is immutable.
* When null, IVMs are emitted as they are written.
*
* @param minimizing the IVM minimization strategy.
* Null indicates that all explicitly-written IVMs will be emitted.
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*
* @see #setIvmMinimizing(IonWriterBuilder.IvmMinimizing)
* @see #getIvmMinimizing()
*
*/
public final IonTextWriterBuilder
withIvmMinimizing(IvmMinimizing minimizing)
{
IonTextWriterBuilder b = mutable();
b.setIvmMinimizing(minimizing);
return b;
}
//-------------------------------------------------------------------------
/**
* Gets the strategy for reducing or eliminating local symbol tables.
* By default, LST data is emitted as received or when necessary
* (for example, binary data will always collect and emit local symbols).
*
* @see #setLstMinimizing(LstMinimizing)
* @see #withLstMinimizing(LstMinimizing)
*
*/
public final LstMinimizing getLstMinimizing()
{
return myLstMinimizing;
}
/**
* Sets the strategy for reducing or eliminating local symbol tables.
* By default, LST data is emitted as received or when necessary
* (for example, binary data will always collect and emit local symbols).
*
* @param minimizing the LST minimization strategy.
* Null indicates that LSTs will be emitted as received.
*
* @see #getLstMinimizing()
* @see #withLstMinimizing(LstMinimizing)
*
* @throws UnsupportedOperationException if this is immutable.
*
*/
public void setLstMinimizing(LstMinimizing minimizing)
{
mutationCheck();
myLstMinimizing = minimizing;
}
/**
* Sets the strategy for reducing or eliminating local symbol tables.
* By default, LST data is emitted as received or when necessary
* (for example, binary data will always collect and emit local symbols).
*
* @param minimizing the LST minimization strategy.
* Null indicates that LSTs will be emitted as received.
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*
* @see #getLstMinimizing()
* @see #setLstMinimizing(LstMinimizing)
*
*/
public final IonTextWriterBuilder
withLstMinimizing(LstMinimizing minimizing)
{
IonTextWriterBuilder b = mutable();
b.setLstMinimizing(minimizing);
return b;
}
//-------------------------------------------------------------------------
/**
* Gets the length beyond which string and clob content will be rendered
* as triple-quoted "long strings".
* At present, such content will only line-break on extant newlines.
*
* @return the threshold for printing triple-quoted strings and clobs.
* Zero means no limit.
*
* @see #setLongStringThreshold(int)
* @see #withLongStringThreshold(int)
*/
public final int getLongStringThreshold()
{
return myLongStringThreshold;
}
/**
* Sets the length beyond which string and clob content will be rendered
* as triple-quoted "long strings".
* At present, such content will only line-break on extant newlines.
*
* @param threshold the new threshold; zero means none.
*
* @see #getLongStringThreshold()
* @see #withLongStringThreshold(int)
*
* @throws UnsupportedOperationException if this is immutable.
*/
public void setLongStringThreshold(int threshold)
{
mutationCheck();
myLongStringThreshold = threshold;
}
/**
* Declares the length beyond which string and clob content will be rendered
* as triple-quoted "long strings".
* At present, such content will only line-break on extant newlines.
*
* @param threshold the new threshold; zero means none.
*
* @see #getLongStringThreshold()
* @see #setLongStringThreshold(int)
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*/
public final IonTextWriterBuilder withLongStringThreshold(int threshold)
{
IonTextWriterBuilder b = mutable();
b.setLongStringThreshold(threshold);
return b;
}
//=========================================================================
/**
* Gets the character sequence that will be written as a line separator.
* The default is {@link NewLineType#PLATFORM_DEPENDENT}
*
* @return the character sequence to be written between top-level values; null means the default should be used.
*
* @see #setNewLineType(NewLineType)
* @see #withNewLineType(NewLineType)
*/
public final NewLineType getNewLineType()
{
return myNewLineType;
}
/**
* Sets the character sequence that will be written as a line separator.
* The default is {@link NewLineType#PLATFORM_DEPENDENT}
*
* @param newLineType the character sequence to be written between top-level values; null means the default should be used.
*
* @see #getNewLineType()
* @see #withNewLineType(NewLineType)
*
* @throws UnsupportedOperationException if this is immutable.
*/
public void setNewLineType(NewLineType newLineType)
{
mutationCheck();
this.myNewLineType = newLineType;
}
/**
* Declares the character sequence that will be written as a line separator.
* The default is {@link NewLineType#PLATFORM_DEPENDENT}
*
* @param newLineType the character sequence to be written between top-level values; null means the default should be used.
*
* @see #getNewLineType()
* @see #setNewLineType(NewLineType)
*
* @return this instance, if mutable;
* otherwise a mutable copy of this instance.
*/
public final IonTextWriterBuilder withNewLineType(NewLineType newLineType)
{
IonTextWriterBuilder b = mutable();
b.setNewLineType(newLineType);
return b;
}
//=========================================================================
/**
* Gets whether each top level value for standard printing should start on a new line. The default value is {@code false}.
* When false, the IonTextWriter will insert a single space character (U+0020) between top-level values.
* When pretty-printing, this setting is ignored; the pretty printer will always start top-level values on a new line.
*
* @return value indicating whether standard printing will insert a newline between top-level values
*
* @see #setWriteTopLevelValuesOnNewLines(boolean)
* @see #withWriteTopLevelValuesOnNewLines(boolean)
*/
public final boolean getWriteTopLevelValuesOnNewLines()
{
return myTopLevelValuesOnNewLines;
}
/**
* Sets whether each top level value for standard printing should start on a new line. The default value is {@code false}.
* When false, the IonTextWriter will insert a single space character (U+0020) between top-level values.
* When pretty-printing, this setting is ignored; the pretty printer will always start top-level values on a new line.
*
* @param writeTopLevelValuesOnNewLines value indicating whether standard printing will insert a newline between top-level values
*
* @see #getWriteTopLevelValuesOnNewLines()
* @see #withWriteTopLevelValuesOnNewLines(boolean)
*/
public void setWriteTopLevelValuesOnNewLines(boolean writeTopLevelValuesOnNewLines)
{
mutationCheck();
myTopLevelValuesOnNewLines = writeTopLevelValuesOnNewLines;
}
/**
* Declares whether each top level value for standard printing should start on a new line. The default value is {@code false}.
* When false, the IonTextWriter will insert a single space character (U+0020) between top-level values.
* When pretty-printing, this setting is ignored; the pretty printer will always start top-level values on a new line.
*
* @param writeTopLevelValuesOnNewLines value indicating whether standard printing will insert a newline between top-level values
*
* @see #getWriteTopLevelValuesOnNewLines()
* @see #setWriteTopLevelValuesOnNewLines(boolean)
*/
public final IonTextWriterBuilder withWriteTopLevelValuesOnNewLines(boolean writeTopLevelValuesOnNewLines)
{
IonTextWriterBuilder b = mutable();
b.setWriteTopLevelValuesOnNewLines(writeTopLevelValuesOnNewLines);
return b;
}
//=========================================================================
/**
* Gets the maximum number of digits of fractional second precision allowed to be written for timestamp values.
*
* @return the currently configured maximum.
*
* @see #setMaximumTimestampPrecisionDigits(int)
* @see #withMaximumTimestampPrecisionDigits(int)
*/
public final int getMaximumTimestampPrecisionDigits() {
return myMaximumTimestampPrecisionDigits;
}
/**
* Sets the maximum number of digits of fractional second precision allowed to be written for timestamp values.
* Default: {@link Timestamp#DEFAULT_MAXIMUM_DIGITS_TEXT}.
*
* @see #getMaximumTimestampPrecisionDigits()
* @see #withMaximumTimestampPrecisionDigits(int)
*/
public void setMaximumTimestampPrecisionDigits(int maximumTimestampPrecisionDigits) {
mutationCheck();
myMaximumTimestampPrecisionDigits = maximumTimestampPrecisionDigits;
}
/**
* Sets the maximum number of digits of fractional second precision allowed to be written for timestamp values.
* Default: {@link Timestamp#DEFAULT_MAXIMUM_DIGITS_TEXT}.
*
* @return this instance, if mutable; otherwise a mutable copy of this instance.
*
* @see #getMaximumTimestampPrecisionDigits()
* @see #setMaximumTimestampPrecisionDigits(int)
*/
public final IonTextWriterBuilder withMaximumTimestampPrecisionDigits(int maximumTimestampPrecisionDigits) {
IonTextWriterBuilder b = mutable();
b.setMaximumTimestampPrecisionDigits(maximumTimestampPrecisionDigits);
return b;
}
//=========================================================================
/**
* Creates a new writer that will write text to the given output
* stream.
*
* If you have an {@link OutputStream}, you'll get better performance using
* {@link #build(OutputStream)} as opposed to wrapping your stream in an
* {@link Appendable} and calling this method.
*
* @param out the stream that will receive Ion text data.
* Must not be null.
*
* @return a new {@link IonWriter} instance; not {@code null}.
*/
public abstract IonWriter build(Appendable out);
}