package com.fasterxml.jackson.dataformat.ion;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import com.fasterxml.jackson.core.Base64Variant;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.StreamWriteCapability;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.base.GeneratorBase;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.core.util.JacksonFeatureSet;
import com.fasterxml.jackson.dataformat.ion.polymorphism.IonAnnotationTypeSerializer;
import com.amazon.ion.IonType;
import com.amazon.ion.IonValue;
import com.amazon.ion.IonWriter;
import com.amazon.ion.Timestamp;
public class IonGenerator
extends GeneratorBase
{
protected final IonWriter _writer;
protected final boolean _ionWriterIsManaged;
protected final IOContext _ioContext;
protected final Closeable _destination;
public IonGenerator(int features, ObjectCodec codec,
IonWriter ion, boolean ionWriterIsManaged, IOContext ctxt, Closeable dst)
{
super(features, codec);
_writer = ion;
_ionWriterIsManaged = ionWriterIsManaged;
_ioContext = ctxt;
_destination = dst;
}
@Override
public Version version() {
return PackageVersion.VERSION;
}
@Override
public void close() throws IOException
{
if (!_closed) {
_closed = true;
if (_ionWriterIsManaged) {
_writer.close();
}
if (_ioContext.isResourceManaged()) {
_destination.close();
} else {
if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
if (_destination instanceof Flushable) {
((Flushable) _destination).flush();
}
}
}
}
}
@Override
public void flush() throws IOException
{
if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
Object dst = _ioContext.getSourceReference();
if (dst instanceof Flushable) {
((Flushable) dst).flush();
}
}
}
@Override
public boolean isClosed() {
return _closed;
}
@Override
public boolean canWriteTypeId() { return true; }
@Override
public boolean canWriteBinaryNatively() { return true; }
@Override
public JacksonFeatureSet<StreamWriteCapability> getWriteCapabilities() {
return DEFAULT_BINARY_WRITE_CAPABILITIES;
}
@Override
public void writeNumber(int value) throws IOException, JsonGenerationException {
_verifyValueWrite("write numeric value");
_writer.writeInt((long)value);
}
@Override
public void writeNumber(long value) throws IOException, JsonGenerationException {
_verifyValueWrite("write numeric value");
_writer.writeInt(value);
}
@Override
public void writeNumber(BigInteger value) throws IOException, JsonGenerationException {
if (value == null) {
writeNull();
} else {
_verifyValueWrite("write numeric value");
_writer.writeInt(value);
}
}
@Override
public void writeNumber(double value) throws IOException, JsonGenerationException {
_verifyValueWrite("write numeric value");
_writer.writeFloat(value);
}
@Override
public void writeNumber(float value) throws IOException, JsonGenerationException {
_verifyValueWrite("write numeric value");
_writer.writeFloat((double) value);
}
@Override
public void writeNumber(BigDecimal value) throws IOException, JsonGenerationException {
if (value == null) {
writeNull();
} else {
_verifyValueWrite("write numeric value");
_writer.writeDecimal(value);
}
}
@Override
public void writeNumber(String value) throws IOException, JsonGenerationException, UnsupportedOperationException {
writeString(value);
}
public void writeSymbol(String value) throws JsonGenerationException, IOException {
_verifyValueWrite("write symbol value");
_writer.writeSymbol(value);
}
public void annotateNextValue(String annotation) {
_writer.addTypeAnnotation(annotation);
}
public void writeDate(Calendar value) throws JsonGenerationException, IOException {
_verifyValueWrite("write date value");
_writer.writeTimestamp(Timestamp.forCalendar(value));
}
@Override
public void writeString(String value) throws IOException, JsonGenerationException {
_verifyValueWrite("write text value");
_writer.writeString(value);
}
@Override
public void writeString(char[] buffer, int offset, int length) throws IOException, JsonGenerationException {
writeString(new String(buffer, offset, length));
}
@Override
public void writeUTF8String(byte[] buffer, int offset, int length) throws IOException, JsonGenerationException {
writeString(new String(buffer, offset, length, "UTF-8"));
}
@Override
public void writeRaw(String value) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRaw(char value) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRaw(String value, int arg1, int arg2) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRaw(char[] value, int arg1, int arg2) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRawValue(String value) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRawValue(String value, int arg1, int arg2) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRawValue(char[] value, int arg1, int arg2) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException, JsonGenerationException {
_reportNoRaw();
}
@Override
public void writeBinary(Base64Variant b64v, byte[] data, int offset, int length) throws IOException, JsonGenerationException {
_verifyValueWrite("write binary data");
_writer.writeBlob(data, offset, length);
}
@Override
public void writeBoolean(boolean value) throws IOException, JsonGenerationException {
_verifyValueWrite("write boolean");
_writer.writeBool(value);
}
@Override
public void writeNull() throws IOException, JsonGenerationException {
_verifyValueWrite("write null");
_writer.writeNull();
}
public void writeNull(IonType ionType) throws IOException, JsonGenerationException {
_verifyValueWrite("write null");
_writer.writeNull(ionType);
}
@Override
public void writeObject(Object pojo) throws IOException, JsonProcessingException
{
if (pojo == null) {
writeNull();
} else {
if (_objectCodec == null) {
throw new IllegalStateException("No ObjectCodec defined for the generator, can not serialize regular Java objects");
}
_objectCodec.writeValue(this, pojo);
}
}
public void writeValue(IonValue value) throws IOException {
_verifyValueWrite("write ion value");
if (value == null) {
_writer.writeNull();
} else {
value.writeTo(_writer);
}
}
public void writeValue(Timestamp value) throws IOException {
_verifyValueWrite("write timestamp");
if (value == null) {
_writer.writeNull();
} else {
_writer.writeTimestamp(value);
}
}
@Override
protected void _releaseBuffers() {
}
@Override
protected void _verifyValueWrite(String msg) throws IOException, JsonGenerationException
{
int status = _writeContext.writeValue();
if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
_reportError("Can not "+msg+", expecting field name");
}
if (_cfgPrettyPrinter != null) {
switch (status) {
case JsonWriteContext.STATUS_OK_AFTER_COMMA:
_cfgPrettyPrinter.writeArrayValueSeparator(this);
break;
case JsonWriteContext.STATUS_OK_AFTER_COLON:
_cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
break;
case JsonWriteContext.STATUS_OK_AFTER_SPACE:
_cfgPrettyPrinter.writeRootValueSeparator(this);
break;
case JsonWriteContext.STATUS_OK_AS_IS:
if (_writeContext.inArray()) {
_cfgPrettyPrinter.beforeArrayValues(this);
} else if (_writeContext.inObject()) {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
break;
default:
throw new IllegalStateException("Should never occur; status "+status);
}
}
}
@Override
public void writeEndArray() throws IOException, JsonGenerationException {
_writeContext = _writeContext.getParent();
_writer.stepOut();
}
@Override
public void writeEndObject() throws IOException, JsonGenerationException {
_writeContext = _writeContext.getParent();
_writer.stepOut();
}
@Override
public void writeFieldName(String value) throws IOException, JsonGenerationException {
int status = _writeContext.writeFieldName(value);
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
_writeFieldName(value);
}
protected void _writeFieldName(String value) throws IOException, JsonGenerationException {
_writer.setFieldName(value);
}
@Override
public void writeStartArray() throws IOException, JsonGenerationException {
_verifyValueWrite("start an array");
_writeContext = _writeContext.createChildArrayContext();
_writer.stepIn(IonType.LIST);
}
@Override
public void writeStartObject() throws IOException, JsonGenerationException {
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
_writer.stepIn(IonType.STRUCT);
}
@Override
public void writeTypeId(Object rawId) throws IOException {
if (rawId instanceof String[]) {
String[] ids = (String[]) rawId;
for (String id : ids) {
annotateNextValue(id);
}
} else {
annotateNextValue(String.valueOf(rawId));
}
}
@Override
public WritableTypeId writeTypePrefix(WritableTypeId typeIdDef) throws IOException
{
final JsonToken valueShape = typeIdDef.valueShape;
typeIdDef.wrapperWritten = false;
writeTypeId(typeIdDef.id);
if (valueShape == JsonToken.START_OBJECT) {
writeStartObject(typeIdDef.forValue);
} else if (valueShape == JsonToken.START_ARRAY) {
writeStartArray();
}
return typeIdDef;
}
@Override
public String toString() {
return "["+getClass().getSimpleName()+", Ion writer: "+_writer+"]";
}
protected void _reportNoRaw() throws IOException {
throw new IOException("writeRaw() functionality not available with Ion backend");
}
}