From 65f80aac2be7ea042f5f111b94516b03e43b1759 Mon Sep 17 00:00:00 2001 From: Matthew Pope Date: Wed, 22 Nov 2023 13:26:07 -0800 Subject: [PATCH 1/4] Adds Ion11Writer interface --- .../java/com/amazon/ion/impl/Ion11Writer.kt | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/main/java/com/amazon/ion/impl/Ion11Writer.kt diff --git a/src/main/java/com/amazon/ion/impl/Ion11Writer.kt b/src/main/java/com/amazon/ion/impl/Ion11Writer.kt new file mode 100644 index 0000000000..a368ed3ecb --- /dev/null +++ b/src/main/java/com/amazon/ion/impl/Ion11Writer.kt @@ -0,0 +1,153 @@ +package com.amazon.ion.impl + +import com.amazon.ion.Decimal +import com.amazon.ion.IonType +import com.amazon.ion.Timestamp +import java.math.BigDecimal +import java.math.BigInteger +import java.time.Instant +import java.time.LocalDate + +/** + * Writes Ion 1.1 data to an output source. + * + * This interface allows the user to write Ion data without being concerned about which output format is being used. + */ +interface Ion11Writer { + + /** + * 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 (`stepped out`)[stepOut]. + * + * Implementations should allow the application to continue writing further top-level values following the semantics + * for concatenating Ion data streams. + */ + fun finish() + + /** + * 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 [finish] before closing the underlying output stream. + * If not, the resulting data may be incomplete and invalid Ion. + */ + fun close() + + /** Returns true if the writer is currently in a struct (indicating that field names are required). */ + fun isInStruct(): Boolean + + /** Returns the current depth of containers the writer is at. This is 0 if the writer is at top-level. */ + fun depth(): Int + + /** + * Writes the Ion 1.1 IVM. IVMs can only be written at the top level of an Ion stream. + * @throws com.amazon.ion.IonException if in any container. + */ + fun writeIVM() + + /** Writes one annotation for the next value. */ + fun writeAnnotations(annotation0: Long) + + /** Writes two annotations for the next value. */ + fun writeAnnotations(annotation0: Long, annotation1: Long) + + /** Writes three or more annotations for the next value. */ + fun writeAnnotations(annotation0: Long, annotation1: Long, vararg annotations: Long) + + /** Writes one annotation for the next value. */ + fun writeAnnotations(annotation0: String) + + /** Writes two annotations for the next value. */ + fun writeAnnotations(annotation0: String, annotation1: String) + + /** Writes three or more annotations for the next value. */ + fun writeAnnotations(annotation0: String, annotation1: String, vararg annotations: String) + + /** + * Writes the field name for the next value. Must be called while in a struct and must be called before [writeAnnotations]. + * @throws com.amazon.ion.IonException if annotations are already written for the value or if not in a struct. + */ + fun writeFieldName(text: String) + + /** + * Writes the field name for the next value. Must be called while in a struct and must be called before [writeAnnotations]. + * @throws com.amazon.ion.IonException if annotations are already written for the value or if not in a struct. + */ + fun writeFieldName(sid: Long) + + fun stepInList(delimited: Boolean) + fun stepInSExp(delimited: Boolean) + + /** + * Delimited struct with FlexSym field names + * Variable length struct with symbol address field names + * Variable length struct with FlexSym field names + * + * @throws com.amazon.ion.IonException if delimited is true and useFlexSym is false. + */ + fun stepInStruct(delimited: Boolean, useFlexSym: Boolean) + + /** + * Steps into a stream. + * A stream is not a container in the Ion data model, but it is a container from an encoding perspective. + */ + fun stepInStream() + + /** + * Writes a macro invocation for the given macro name. + * A macro is not a container in the Ion data model, but it is a container from an encoding perspective. + */ + fun stepInEExp(name: String) + + /** + * Writes a macro invocation for the given id corresponding to a macro in the macro table. + * A macro is not a container in the Ion data model, but it is a container from an encoding perspective. + */ + fun stepInEExp(id: Long) + + /** + * Steps out of the current container. + */ + fun stepOut() + + // TODO: Doc comments for the uninteresting functions + + fun writeNull() + fun writeNull(type: IonType) + + fun writeBool(value: Boolean) + + fun writeInt(value: Byte) + fun writeInt(value: Short) + fun writeInt(value: Int) + fun writeInt(value: Long) + fun writeInt(value: BigInteger) + + fun writeFloat(value: Float) + fun writeFloat(value: Double) + + fun writeDecimal(value: BigDecimal) + fun writeDecimal(value: Decimal) + + fun writeTimestamp(value: Timestamp) + + /** Writes an Ion timestamp with Days precision */ + fun writeTimestamp(value: LocalDate) + + /** Writes an Ion timestamp with 0 offset (UTC) and nanosecond precision. */ + fun writeTimestamp(value: Instant) + + fun writeSymbol(id: Long) + fun writeSymbol(text: CharSequence) + + fun writeString(value: CharSequence) + + fun writeBlob(value: ByteArray) = writeBlob(value, 0, value.size) + fun writeBlob(value: ByteArray, start: Int, length: Int) + + fun writeClob(value: ByteArray) = writeClob(value, 0, value.size) + fun writeClob(value: ByteArray, start: Int, length: Int) +} From 9782d24cddb7ba961a88132c282c76f7e59807b7 Mon Sep 17 00:00:00 2001 From: Matthew Pope Date: Fri, 24 Nov 2023 12:54:53 -0800 Subject: [PATCH 2/4] Adds suggested changes --- .../impl/{Ion11Writer.kt => IonWriter_1_1.kt} | 65 ++++++++++++++----- 1 file changed, 48 insertions(+), 17 deletions(-) rename src/main/java/com/amazon/ion/impl/{Ion11Writer.kt => IonWriter_1_1.kt} (67%) diff --git a/src/main/java/com/amazon/ion/impl/Ion11Writer.kt b/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt similarity index 67% rename from src/main/java/com/amazon/ion/impl/Ion11Writer.kt rename to src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt index a368ed3ecb..0f74e82367 100644 --- a/src/main/java/com/amazon/ion/impl/Ion11Writer.kt +++ b/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt @@ -13,7 +13,7 @@ import java.time.LocalDate * * This interface allows the user to write Ion data without being concerned about which output format is being used. */ -interface Ion11Writer { +interface IonWriter_1_1 { /** * Indicates that writing is completed and all buffered data should be written and flushed as if this were the end @@ -39,7 +39,7 @@ interface Ion11Writer { /** Returns true if the writer is currently in a struct (indicating that field names are required). */ fun isInStruct(): Boolean - /** Returns the current depth of containers the writer is at. This is 0 if the writer is at top-level. */ + /** Returns the current depth of containers the writer is at. This is 0 if the writer is at top-level. */ fun depth(): Int /** @@ -48,29 +48,47 @@ interface Ion11Writer { */ fun writeIVM() - /** Writes one annotation for the next value. */ + /** + * Writes one annotation for the next value. + * [writeAnnotations] may be called more than once to build up a list of annotations. + */ fun writeAnnotations(annotation0: Long) - /** Writes two annotations for the next value. */ + /** + * Writes two annotations for the next value. + * [writeAnnotations] may be called more than once to build up a list of annotations. + */ fun writeAnnotations(annotation0: Long, annotation1: Long) - /** Writes three or more annotations for the next value. */ + /** + * Writes three or more annotations for the next value. + * [writeAnnotations] may be called more than once to build up a list of annotations. + */ fun writeAnnotations(annotation0: Long, annotation1: Long, vararg annotations: Long) - /** Writes one annotation for the next value. */ - fun writeAnnotations(annotation0: String) + /** + * Writes one annotation for the next value. + * [writeAnnotations] may be called more than once to build up a list of annotations. + */ + fun writeAnnotations(annotation0: CharSequence) - /** Writes two annotations for the next value. */ - fun writeAnnotations(annotation0: String, annotation1: String) + /** + * Writes two annotations for the next value. + * [writeAnnotations] may be called more than once to build up a list of annotations. + */ + fun writeAnnotations(annotation0: CharSequence, annotation1: CharSequence) - /** Writes three or more annotations for the next value. */ - fun writeAnnotations(annotation0: String, annotation1: String, vararg annotations: String) + /** + * Writes three or more annotations for the next value. + * [writeAnnotations] may be called more than once to build up a list of annotations. + */ + fun writeAnnotations(annotation0: CharSequence, annotation1: CharSequence, vararg annotations: CharSequence) /** * Writes the field name for the next value. Must be called while in a struct and must be called before [writeAnnotations]. * @throws com.amazon.ion.IonException if annotations are already written for the value or if not in a struct. */ - fun writeFieldName(text: String) + fun writeFieldName(text: CharSequence) /** * Writes the field name for the next value. Must be called while in a struct and must be called before [writeAnnotations]. @@ -78,15 +96,28 @@ interface Ion11Writer { */ fun writeFieldName(sid: Long) + /** + * Steps into a List. + * + * The [delimited] parameter is a suggestion. Implementations may ignore it if it is not relevant for that + * particular implementation. All implementations must document their specific behavior for this method. + */ fun stepInList(delimited: Boolean) + + /** + * Steps into a SExp. + * + * The [delimited] parameter is a suggestion. Implementations may ignore it if it is not relevant for that + * particular implementation. All implementations must document their specific behavior for this method. + */ fun stepInSExp(delimited: Boolean) /** - * Delimited struct with FlexSym field names - * Variable length struct with symbol address field names - * Variable length struct with FlexSym field names + * Steps into a Struct. * - * @throws com.amazon.ion.IonException if delimited is true and useFlexSym is false. + * The [delimited] and [useFlexSym] parameters are suggestions. Implementations may ignore these parameters if they + * are not relevant for that particular implementation. All implementations must document their specific behavior + * for this method. */ fun stepInStruct(delimited: Boolean, useFlexSym: Boolean) @@ -100,7 +131,7 @@ interface Ion11Writer { * Writes a macro invocation for the given macro name. * A macro is not a container in the Ion data model, but it is a container from an encoding perspective. */ - fun stepInEExp(name: String) + fun stepInEExp(name: CharSequence) /** * Writes a macro invocation for the given id corresponding to a macro in the macro table. From 403cacc7a5263042f28ba8105a290abdde20bcd9 Mon Sep 17 00:00:00 2001 From: Matthew Pope Date: Fri, 24 Nov 2023 14:30:15 -0800 Subject: [PATCH 3/4] Changes symbol and template IDs to int; remove some extraneous functions --- .../java/com/amazon/ion/impl/IonWriter_1_1.kt | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt b/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt index 0f74e82367..921b577664 100644 --- a/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt +++ b/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt @@ -52,19 +52,19 @@ interface IonWriter_1_1 { * Writes one annotation for the next value. * [writeAnnotations] may be called more than once to build up a list of annotations. */ - fun writeAnnotations(annotation0: Long) + fun writeAnnotations(annotation0: Int) /** * Writes two annotations for the next value. * [writeAnnotations] may be called more than once to build up a list of annotations. */ - fun writeAnnotations(annotation0: Long, annotation1: Long) + fun writeAnnotations(annotation0: Int, annotation1: Int) /** * Writes three or more annotations for the next value. * [writeAnnotations] may be called more than once to build up a list of annotations. */ - fun writeAnnotations(annotation0: Long, annotation1: Long, vararg annotations: Long) + fun writeAnnotations(annotation0: Int, annotation1: Int, vararg annotations: Int) /** * Writes one annotation for the next value. @@ -94,7 +94,7 @@ interface IonWriter_1_1 { * Writes the field name for the next value. Must be called while in a struct and must be called before [writeAnnotations]. * @throws com.amazon.ion.IonException if annotations are already written for the value or if not in a struct. */ - fun writeFieldName(sid: Long) + fun writeFieldName(sid: Int) /** * Steps into a List. @@ -137,7 +137,7 @@ interface IonWriter_1_1 { * Writes a macro invocation for the given id corresponding to a macro in the macro table. * A macro is not a container in the Ion data model, but it is a container from an encoding perspective. */ - fun stepInEExp(id: Long) + fun stepInEExp(id: Int) /** * Steps out of the current container. @@ -152,7 +152,6 @@ interface IonWriter_1_1 { fun writeBool(value: Boolean) fun writeInt(value: Byte) - fun writeInt(value: Short) fun writeInt(value: Int) fun writeInt(value: Long) fun writeInt(value: BigInteger) @@ -163,6 +162,17 @@ interface IonWriter_1_1 { fun writeDecimal(value: BigDecimal) fun writeDecimal(value: Decimal) + /** + * TODO: Consider adding a function for writing a timestamp that doesn't require creating a [Timestamp] instance, so + * that users don't have to allocate an intermediate between their data type and the Ion writer. E.g.: + * ``` + * fun writeTimestamp(precision: Timestamp.Precision, + * year: Int, month: Int?, day: Int?, + * hour: Int?, minute: Int?, second: Int?, + * fractionalSeconds: BigDecimal?, + * offsetMinutes: Int?) + * ``` + */ fun writeTimestamp(value: Timestamp) /** Writes an Ion timestamp with Days precision */ @@ -171,7 +181,7 @@ interface IonWriter_1_1 { /** Writes an Ion timestamp with 0 offset (UTC) and nanosecond precision. */ fun writeTimestamp(value: Instant) - fun writeSymbol(id: Long) + fun writeSymbol(id: Int) fun writeSymbol(text: CharSequence) fun writeString(value: CharSequence) From 478f53497b7a3b7027f654eebf01929f88675a76 Mon Sep 17 00:00:00 2001 From: Matthew Pope Date: Mon, 27 Nov 2023 09:25:05 -0800 Subject: [PATCH 4/4] Remove method to write timestamp from LocalDate --- src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt b/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt index 921b577664..f85d526c7f 100644 --- a/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt +++ b/src/main/java/com/amazon/ion/impl/IonWriter_1_1.kt @@ -6,7 +6,6 @@ import com.amazon.ion.Timestamp import java.math.BigDecimal import java.math.BigInteger import java.time.Instant -import java.time.LocalDate /** * Writes Ion 1.1 data to an output source. @@ -175,9 +174,6 @@ interface IonWriter_1_1 { */ fun writeTimestamp(value: Timestamp) - /** Writes an Ion timestamp with Days precision */ - fun writeTimestamp(value: LocalDate) - /** Writes an Ion timestamp with 0 offset (UTC) and nanosecond precision. */ fun writeTimestamp(value: Instant)