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

software.amazon.ion.IonWriter Maven / Gradle / Ivy

There is a newer version: 1.5.1
Show newest version
/*
 * Copyright 2008-2016 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://aws.amazon.com/apache2.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 software.amazon.ion;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import software.amazon.ion.system.IonTextWriterBuilder;
import software.amazon.ion.util.IonStreamUtils;

/**
 * Writes Ion data to an output source.
 *
 * This interface allows the user to write Ion data without being concerned
 * about which output format is being used.
 * 

* WARNING: This interface should not be implemented or extended by * code outside of this library. * We still have some work to do before this interface is stable. * See issue amzn/ion-java#10 *

* A value is written via the set of typed {@code write*()} methods such as * {@link #writeBool(boolean)} and {@link #writeInt(long)}. * Each of these methods outputs a single Ion value, and afterwards the writer * is prepared to receive the data for the next sibling value. *

* Any type annotations must be set before the value is written. * Once the value has been written the "pending annotations" are erased, * so they are must be set again if they need to be applied to the next value. *

* Similarly the field name must be set before the value is * written (assuming the value is a field in a structure). The field name * is also "erased" once used, so it must be set for each field. *

* To write a container, first write any annotations and/or field name * applicable to the container itself. * Then call {@link #stepIn(IonType)} with the desired container type. * Then write each child value in order. * Finally, call {@link #stepOut()} to complete the container. *

* Once all the top-level values have been written (and stepped-out back to * the starting level), the caller must {@link #close()} the writer * (or at least {@link #finish()} it) before accessing * the data written to the underlying data sink * (for example, via {@link ByteArrayOutputStream#toByteArray()}). * The writer may have internal buffers and without closing or finishing it, * it may not have written everything to the underlying data sink. In addition, * {@link #flush()} isn't guaranteed to be sufficient for all implementations. * *

Exception Handling

* {@code IonWriter} is a generic interface for generating Ion data, and it's * not possible to fully specify the set of exceptions that could be thrown * from the underlying data sink. Thus all failures are thrown as instances * of {@link IonException}, wrapping the originating cause. If an application * wants to handle (say) {@link IOException}s specially, then it needs to * extract that from the wrappers; the documentation of {@link IonException} * explains how to do that. * * @see IonStreamUtils * @see IonTextWriterBuilder */ public interface IonWriter extends Closeable, Flushable { /** * Gets the symbol table that is currently in use by the writer. * While writing a number of values the symbol table will be * populated with any added symbols. *

* Note that the table may be replaced during processing. For example, * the stream may start out with a system table that's later replaced by a * local table in order to store newly-encountered symbols. *

* When this method returns a local table, it may be * {@linkplain SymbolTable#isReadOnly() mutable}, meaning that additional * symbols may be interned until it is * {@linkplain SymbolTable#makeReadOnly() made read-only}. Note that * manually mutating local symbol tables is a deprecated feature; * please instead use * {@link IonSystem#newBinaryWriter(java.io.OutputStream, SymbolTable...)} * or {@link IonSystem#newTextWriter(java.io.OutputStream, SymbolTable...)} * to provide custom symbol table(s) to writers upon construction. * * @return current symbol table */ public SymbolTable getSymbolTable(); /** * Flushes this writer by writing any buffered output to the underlying * output target. *

* For some implementations this may have no effect even when some data is * buffered, because it's not always possible to fully write partial data. * In particular, when writing binary Ion data, Ion's length-prefixed * encoding requires a complete top-level value to be written at once. *

* Furthermore, when writing binary Ion data, nothing can be * flushed until the writer knows that no more local symbols can be * encountered. This can be accomplished via {@link #finish()} or by * making the {@linkplain #getSymbolTable() local symbol table} * {@linkplain SymbolTable#makeReadOnly() read-only}. * * @throws IOException if thrown by the underlying output target. * * @see #finish() */ public void flush() throws IOException; /** * Indicates that writing is completed and all buffered data should be * written and flushed as if this were the end of the Ion data stream. * For example, an Ion binary writer will finalize any local symbol table, * write all top-level values, and then flush. *

* This method may only be called when all top-level values are * completely written and {@linkplain #stepOut() stepped-out}. *

* Implementations should allow the application to continue writing further * top-level values following the semantics for concatenating Ion data * streams. If another top-level value is written, the result must behave * as if it were preceded by an Ion version marker, resetting the stream * context as if this were a new stream. (Whether or not an IVM is written * may depend upon the writer's configuration; see * {@link software.amazon.ion.system.IonWriterBuilder.IvmMinimizing * IvmMinimizing}.) *

* This feature can be used to flush reliably before writing more values. * Think about a long-running stream of binary values: without finishing, * all the values would continue to buffer since the encoder keeps * expecting more local symbols (which must be written into the local * symbol table that precedes all top-level values). Such an application * can finish occasionally to flush the data out, then continue writing * more data using a fresh local symbol table. * * @throws IOException if thrown by the underlying output target. * @throws IllegalStateException when not between top-level values. * * @see #flush() * @see #close() */ public void finish() throws IOException; /** * Closes this stream and releases any system resources associated with it. * If the stream is already closed then invoking this method has no effect. *

* If the cursor is between top-level values, this method will * {@link #finish()} before closing the underlying output stream. * If not, the resulting data may be incomplete and invalid Ion. *

* In other words: unless you're recovering from a failure condition, * don't close the writer until you've * {@linkplain #stepOut() stepped-out} back to the starting level. * * @throws IOException if thrown by the underlying output target. * * @see #finish() */ public void close() throws IOException; /** * Sets the pending field name to the given text. *

* The pending field name is cleared when the current value is * written via {@link #stepIn(IonType) stepIn()} or one of the * {@code write*()} methods. * * @param name text of the field name * * @throws IllegalStateException if the current container isn't a struct, * that is, if {@link #isInStruct()} is false. * @throws NullPointerException if {@code name} is null. */ public void setFieldName(String name); /** * Sets the pending field name to the given token. *

* The pending field name is cleared when the current value is * written via {@link #stepIn(IonType) stepIn()} or one of the * {@code write*()} methods. * * @param name text of the field name * * @throws IllegalStateException if the current container isn't a struct, * that is, if {@link #isInStruct()} is false. * @throws NullPointerException if {@code name} is null. * */ public void setFieldNameSymbol(SymbolToken name); /** * Sets the full list of pending annotations to the given text symbols. * Any pending annotations are cleared. * The contents of the {@code annotations} array are copied into this * writer, so the caller does not need to preserve the array. *

* The list of pending annotations is cleared when the current value is * written via {@link #stepIn(IonType) stepIn()} or one of the * {@code write*()} methods. * * @param annotations string array with the annotations. * If null or empty, any pending annotations are cleared. */ public void setTypeAnnotations(String... annotations); /** * Sets the full list of pending annotations to the given symbols. * Any pending annotations are cleared. * The contents of the {@code annotations} array are copied into this * writer, so the caller does not need to preserve the array. *

* The list of pending annotations is cleared when the current value is * written via {@link #stepIn(IonType) stepIn()} or one of the * {@code write*()} methods. *

* This is an "expert method": correct use requires deep understanding * of the Ion binary format. You almost certainly don't want to use it. * * @param annotations * If null or empty, any pending annotations are cleared. * */ public void setTypeAnnotationSymbols(SymbolToken... annotations); /** * Adds a given string to the list of pending annotations. *

* The list of pending annotations is cleared when the current value is * written via {@link #stepIn(IonType) stepIn()} or one of the * {@code write*()} methods. * * @param annotation string annotation to append to the annotation list */ public void addTypeAnnotation(String annotation); //========================================================================= // Container navigation /** * Writes the beginning of a non-null container (list, sexp, or struct). * This must be matched by a call to {@link #stepOut()} after the last * child value. *

* This method is not used to write {@code null.list} et al. * To write null values use {@link #writeNull(IonType)}. * * @param containerType must be one of * {@link IonType#LIST}, {@link IonType#SEXP}, or {@link IonType#STRUCT}. */ public void stepIn(IonType containerType) throws IOException; /** * Writes the end of the current container, returning this writer to the * context of parent container. * Invocation of this method must match a preceding call to * {@link #stepIn(IonType)}. */ public void stepOut() throws IOException; /** * Determines whether values are being written as fields of a struct. * This is especially useful when it is not clear whether field names need * to be written or not. * * @return true when the parent is a struct. */ public boolean isInStruct(); //========================================================================= // Value writing /** * Writes the current value from a reader. *

* This method also writes annotations and field names (if in a struct), * and performs a deep write, including the contents of * any containers encountered. */ public void writeValue(IonReader reader) throws IOException; /** * Writes a reader's current value, and all following values until the end * of the current container. If there's no current value then this method * calls {@link IonReader#next()} to get going. *

* This method iterates until {@link IonReader#next()} returns {@code null} * and does not {@linkplain IonReader#stepOut() step out} to the container * of the current cursor position. *

* This method also writes annotations and field names (if in a struct), * and performs a deep write, including the contents of * any containers encountered. */ public void writeValues(IonReader reader) throws IOException; /** * Writes a value of Ion's null type ({@code null} aka {@code null.null}). */ public void writeNull() throws IOException; /** * Writes a null value of a specified Ion type. * * @param type type of the null to be written */ public void writeNull(IonType type) throws IOException; /** * writes a non-null boolean value (true or false) as an IonBool * to output. * @param value true or false as desired */ public void writeBool(boolean value) throws IOException; /** * writes a signed 64 bit value, a Java long, as an IonInt. * @param value signed int to write */ public void writeInt(long value) throws IOException; /** * writes a BigInteger value as an IonInt. If the * BigInteger value is null this writes a null int. * @param value BigInteger to write */ public void writeInt(BigInteger value) throws IOException; /** * writes a 64 bit binary floating point value, a Java double, * as an IonFloat. Currently IonFloat values are output as * 64 bit IEEE 754 big endian values. IonFloat preserves all * valid floating point values, including -0.0, Nan and +/-infinity. * It does not guarantee preservation of -Nan or other less * less "common" values. * @param value double to write */ public void writeFloat(double value) throws IOException; /** * Writes a BigDecimal value as an Ion decimal. Ion uses an * arbitrarily long sign/value and an arbitrarily long signed * exponent to write the value. This preserves * all of the BigDecimal digits, the number of * significant digits. *

* To write a negative zero value, pass this method a * {@link Decimal} instance. * * @param value may be null to represent {@code null.decimal}. */ public void writeDecimal(BigDecimal value) throws IOException; /** * Writes a timestamp value. * * @param value may be null to represent {@code null.timestamp}. */ public void writeTimestamp(Timestamp value) throws IOException; /** * Writes the text of an Ion symbol value. * * @param content may be null to represent {@code null.symbol}. * * @throws IllegalArgumentException if the value contains an invalid UTF-16 * surrogate pair. */ public void writeSymbol(String content) throws IOException; /** * Writes the content of an Ion symbol value. * If the token has text, it is considered canonical and any SID in the * token may be ignored or reassigned. * * @param content may be null to represent {@code null.symbol}. * * @throws IllegalArgumentException if the value contains an invalid UTF-16 * surrogate pair. * */ public void writeSymbolToken(SymbolToken content) throws IOException; /** * Writes a {@link java.lang.String} as an Ion string. Since Ion strings are * UTF-8 and Java Strings are Unicode 16. As such the resulting * lengths may not match. In addition some Java strings are not * valid as they may contain only one of the two needed surrogate * code units necessary to define the Unicode code point to be * output, an exception will be raised if this case is encountered. * * @param value may be null to represent {@code null.string}. * * @throws IllegalArgumentException if the value contains an invalid UTF-16 * surrogate pair. */ public void writeString(String value) throws IOException; /** * write the byte array out as an IonClob value. This copies * the byte array. * * @param value may be null to represent {@code null.clob}. */ public void writeClob(byte[] value) throws IOException; /** * Writes a portion of the byte array out as an IonClob value. This * copies the porition of the byte array that is written. * * @param value bytes to be written. * May be {@code null} to represent {@code null.clob}. * @param start offset of the first byte in value to write * @param len number of bytes to write from value */ public void writeClob(byte[] value, int start, int len) throws IOException; /** * write the byte array out as an IonBlob value. This copies * the byte array. * * @param value may be null to represent {@code null.blob}. */ public void writeBlob(byte[] value) throws IOException; /** * Writes a portion of the byte array out as an IonBlob value. This * copies the portion of the byte array that is written. * * @param value bytes to be written. * May be {@code null} to represent {@code null.blob}. * @param start offset of the first byte in value to write * @param len number of bytes to write from value */ public void writeBlob(byte[] value, int start, int len) throws IOException; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy