public interface IonValue extends Cloneable
WARNING: This interface should not be implemented or extended by code outside of this library.
The IonValue
hierarchy presents a "tree view" of Ion data;
every node in the tree is an instance of this class. Since the Ion
type system is highly orthogonal, most operations use this
base type, and applications will need to examine individual instances and
"downcast" the value to one of the "real" types (e.g.,
IonString
) in order to access the Ion content.
Besides the real types, there are other generic interfaces that can be useful:
IonText
generalizes IonString
and IonSymbol
IonContainer
generalizes
IonList
, IonSexp
, and IonStruct
IonSequence
generalizes IonList
and IonSexp
IonLob
generalizes IonBlob
and IonClob
To determine the real type of a generic IonValue
, there are three
main mechanisms:
instanceof
to look for a desired interface:
if (v instanceof IonString) { useString((IonString) v); } else if (v instanceof IonStruct) { useStruct((IonStruct) v); } // ...
getType()
and then switch
over the resulting
IonType
:
switch (v.getType()) { case IonType.STRING: useString((IonString) v); break; case IonType.STRUCT: useStruct((IonStruct) v); break; // ... }
ValueVisitor
and call accept(ValueVisitor)
:
public class MyVisitor extends AbstractValueVisitor { public void visit(IonString value) { useString(v); } public void visit(IonStruct value) { useStruct(v); } // ... }
IonValue
trees are strictly hierarchical: every node has at most one
parent, as exposed through getContainer()
(and, implicitly,
getFieldName()
). You cannot add an IonValue
instance into
two IonContainer
s; any attempt to do so will result in a
ContainedValueException
. You can of course add the same instance to
multiple "normal" Collections
, since that's stepping outside of the
DOM.
The implication of this design is that you need to be careful when
performing DOM transformations. You must remove a node from its parent
before adding it to another one; removeFromContainer()
is handy.
Alternatively you can clone()
a value, but be aware that cloning is
a deep-copy operation (for the very same single-parent reason).
IonValues
are not safe for use by multiple threads!
Your application must perform its own synchronization if you need to access
IonValues
from multiple threads. This is true even for read-only use
cases, since implementations may perform lazy materialization or other state
changes internally.
Alternatively, you can invoke makeReadOnly()
from a single thread,
after which point the value (and all recursively contained values) will
be immutable and hence thread-safe.
It is important to note that makeReadOnly()
is not guaranteed to
implicitly provide a synchronization point between threads.
This means it is the responsibility of the application to make sure
operations on a thread other than the one that invoked makeReadOnly()
causally happen after that invocation observing the rules of
the Java Memory Model (JSR-133).
Here is an example of ensuring the correct ordering for multiple threads
accessing an IonValue
using a CountDownLatch
to explicitly
create a the temporal relationship:
// ... // Shared Between Threads // ... IonValue value = ...; CountDownLatch latch = new CountDownLatch(1); // ... // Thread 1 // ... value.makeReadOnly(); latch.countDown(); // ... // Thread 2 // ... // before this point operations on 'value' are not defined latch.await(); // we can now operate (in a read-only way) on 'value' value.isNullValue();
In the above, two threads have a reference to value
.
latch
in this example provides a way to synchronize
when makeReadOnly()
happens in the first thread relative
to isNullValue()
being invoked on the second thread.
Modifier and Type | Field and Description |
---|---|
static IonValue[] |
EMPTY_ARRAY
A zero-length immutable
IonValue array. |
Modifier and Type | Method and Description |
---|---|
void |
accept(ValueVisitor visitor)
Entry point for visitor pattern.
|
void |
addTypeAnnotation(String annotation)
Adds a user type annotation to the annotations attached to
this value.
|
void |
clearTypeAnnotations()
Removes all the user type annotations attached to this value.
|
IonValue |
clone()
Creates a copy of this value and all of its children.
|
boolean |
equals(Object other)
Compares two Ion values for structural equality, which means that they
represent the exact same semantics, including annotations, numeric
precision, and so on.
|
IonContainer |
getContainer()
Gets the container of this value,
or
null if this is not part of one. |
int |
getFieldId()
Deprecated.
Use
getFieldNameSymbol() instead. |
String |
getFieldName()
Gets the field name attached to this value,
or
null if this is not part of an IonStruct . |
SymbolToken |
getFieldNameSymbol()
Gets the field name attached to this value as an interned symbol
(text + ID).
|
SymbolTable |
getSymbolTable()
Gets the symbol table used to encode this value.
|
IonSystem |
getSystem()
Gets the system that constructed this value.
|
IonType |
getType()
Gets an enumeration value identifying the core Ion data type of this
object.
|
String[] |
getTypeAnnotations()
Gets this value's user type annotations as text.
|
SymbolToken[] |
getTypeAnnotationSymbols()
Gets this value's user type annotations as interned symbols (text + ID).
|
int |
hashCode()
Returns a hash code consistent with
equals(Object) . |
boolean |
hasTypeAnnotation(String annotation)
Determines whether or not the value is annotated with
a particular user type annotation.
|
boolean |
isNullValue()
Determines whether this in an Ion null value, e.g.,
null or null.string . |
boolean |
isReadOnly()
Determines whether this value is read-only.
|
void |
makeReadOnly()
Marks this instance and its children to be immutable.
|
boolean |
removeFromContainer()
Removes this value from its container, if any.
|
void |
removeTypeAnnotation(String annotation)
Removes a user type annotation from the list of annotations
attached to this value.
|
void |
setTypeAnnotations(String... annotations)
Replaces all type annotations with the given text.
|
void |
setTypeAnnotationSymbols(SymbolToken... annotations)
Replaces all type annotations with the given symbol tokens.
|
IonValue |
topLevelValue()
Finds the top level value above this value.
|
String |
toPrettyString()
Returns a pretty-printed Ion text representation of this value, using
the settings of
IonTextWriterBuilder.pretty() . |
String |
toString()
Returns a non-canonical Ion-formatted ASCII representation of
this value.
|
String |
toString(IonTextWriterBuilder writerBuilder)
Returns an Ion text representation of this value, using the settings
from the given builder.
|
void |
writeTo(IonWriter writer)
Copies this value to the given
IonWriter . |
static final IonValue[] EMPTY_ARRAY
IonValue
array.IonType getType()
null
enumeration value.boolean isNullValue()
null
or null.string
.
Note that there are unique null values for each Ion type.true
if this value is one of the Ion null values.boolean isReadOnly()
true
if this value is read-only and safe for
multi-threaded reads.makeReadOnly()
SymbolTable getSymbolTable()
null
if this value is not
currently backed by binary-encoded data.String getFieldName()
null
if this is not part of an IonStruct
.UnknownSymbolException
- if the field name has unknown text.SymbolToken getFieldNameSymbol()
@Deprecated int getFieldId()
getFieldNameSymbol()
instead.IonStruct
. If this is not a field, or if the symbol ID cannot be
determined, this method returns a value less than one.IonContainer getContainer()
null
if this is not part of one.boolean removeFromContainer()
true
if this value was in a container before this method
was called.IonValue topLevelValue()
IonDatagram
.UnsupportedOperationException
- if this is an IonDatagram
.String[] getTypeAnnotations()
null
) if there are none.UnknownSymbolException
- if any annotation has unknown text.SymbolToken[] getTypeAnnotationSymbols()
null
) if there are none.boolean hasTypeAnnotation(String annotation)
annotation
- as a string value.true
if this value has the annotation.void setTypeAnnotations(String... annotations)
annotations
- the new annotations. If null or empty array, then
all annotations are removed. Any duplicates are preserved.NullPointerException
- if any of the annotations are nullvoid setTypeAnnotationSymbols(SymbolToken... annotations)
annotations
array are copied into this
writer, so the caller does not need to preserve the array.
This is an "expert method": correct use requires deep understanding of the Ion binary format. You almost certainly don't want to use it.
annotations
- the new annotations.
If null or empty array, then all annotations are removed.
Any duplicates are preserved.void clearTypeAnnotations()
void addTypeAnnotation(String annotation)
annotation
- as a string value.void removeTypeAnnotation(String annotation)
annotation
- as a string value.
If null or empty, the method has no effect.void writeTo(IonWriter writer)
IonWriter
.
This method writes annotations and field names (if in a struct), and performs a deep write, including the contents of any containers encountered.
void accept(ValueVisitor visitor) throws Exception
visit
method on the visitor
. For example, instances of
IonBool
will invoke ValueVisitor.visit(IonBool)
.visitor
- will have one of its visit
methods called.Exception
- any exception thrown by the visitor is propagated.NullPointerException
- if visitor
is
null
.void makeReadOnly()
After this method completes, any attempt to change the state of this
instance, or of any contained value, will trigger a
ReadOnlyValueException
.
isReadOnly()
IonSystem getSystem()
IonValue clone() throws UnknownSymbolException
isReadOnly()
.
The cloned value will be created in the context of the same
ValueFactory
as this instance; if you want a copy using a
different factory, then use ValueFactory.clone(IonValue)
instead.
UnknownSymbolException
- if any part of this value has unknown text but known Sid for
its field name, annotation or symbol.String toString()
For more configurable rendering, see
IonTextWriterBuilder
.
This is not the correct way to retrieve the content of an
IonString
or IonSymbol
!
Use IonText.stringValue()
for that purpose.
ionSystem.newString("Levi's").toString() => "\"Levi's\"" ionSystem.newString("Levi's").stringValue() => "Levi's" ionSystem.newSymbol("Levi's").toString() => "'Levi\\'s'" ionSystem.newSymbol("Levi's").stringValue() => "Levi's"
toString
in class Object
IonText.stringValue()
,
toString(IonTextWriterBuilder)
,
toPrettyString()
String toPrettyString()
IonTextWriterBuilder.pretty()
.
The specific 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.
String toString(IonTextWriterBuilder writerBuilder)
writerBuilder
- the configuration that will be used for writing
data to a string.boolean equals(Object other)
equals
in class Object
other
- The value to compare with.IonValue
that
is semantically identical within the Ion data model, including
precision and annotations.Equivalence
int hashCode()
equals(Object)
.