/*
 * Copyright 2012-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 com.fasterxml.jackson.dataformat.ion;

import java.io.CharArrayReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;

import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.io.UTF8Writer;
import com.fasterxml.jackson.core.util.TextBuffer;

import com.amazon.ion.IonReader;
import com.amazon.ion.IonSystem;
import com.amazon.ion.IonValue;
import com.amazon.ion.IonWriter;
import com.amazon.ion.system.IonSystemBuilder;

Sub-class of JsonFactory that will work on Ion content, instead of JSON content.
/** * Sub-class of {@link JsonFactory} that will work on Ion content, instead of JSON * content. */
@SuppressWarnings("resource") public class IonFactory extends JsonFactory { private static final long serialVersionUID = 1L; public final static String FORMAT_NAME_ION = "AmazonIon"; protected final IonSystem _system;
Whether we will produce binary or text Ion writers: default is textual.
/** * Whether we will produce binary or text Ion writers: default is textual. */
protected boolean _cfgCreateBinaryWriters = false;
Bitfield (set of flags) of all parser features that are enabled by default.
/** * Bitfield (set of flags) of all parser features that are enabled * by default. */
protected final static int DEFAULT_ION_PARSER_FEATURE_FLAGS = IonParser.Feature.collectDefaults();
Bitfield (set of flags) of all generator features that are enabled by default.
/** * Bitfield (set of flags) of all generator features that are enabled * by default. */
protected final static int DEFAULT_ION_GENERATOR_FEATURE_FLAGS = IonGenerator.Feature.collectDefaults(); protected int _ionParserFeatures = DEFAULT_ION_PARSER_FEATURE_FLAGS; protected int _ionGeneratorFeatures = DEFAULT_ION_GENERATOR_FEATURE_FLAGS; public IonFactory() { this((ObjectCodec) null); } public IonFactory(ObjectCodec mapper) { this(mapper, IonSystemBuilder.standard().build()); } public IonFactory(ObjectCodec mapper, IonSystem system) { super(mapper); _system = system; } protected IonFactory(IonFactory src, ObjectCodec oc) { super(src, oc); // 21-Feb-2017, tatu: Not 100% sure if this should be made copy of // too; for now assume it may be shared. _system = src._system; _cfgCreateBinaryWriters = src._cfgCreateBinaryWriters; }
Constructors used by IonFactoryBuilder for instantiation.
/** * Constructors used by {@link IonFactoryBuilder} for instantiation. */
protected IonFactory(IonFactoryBuilder b) { super(b, false); _cfgCreateBinaryWriters = b.willCreateBinaryWriters(); _system = b.ionSystem(); _ionParserFeatures = b.formatParserFeaturesMask(); _ionGeneratorFeatures = b.formatGeneratorFeaturesMask(); } @Override public IonFactoryBuilder rebuild() { return new IonFactoryBuilder(this); }
Method for creating IonFactory that will create binary (not textual) writers.
/** * Method for creating {@link IonFactory} that will * create binary (not textual) writers. */
public static IonFactory forBinaryWriters() { return new IonFactoryBuilder(true).build(); }
Method for creating IonFactory that will create textual (not binary) writers.
/** * Method for creating {@link IonFactory} that will * create textual (not binary) writers. */
public static IonFactory forTextualWriters() { return new IonFactoryBuilder(false).build(); }
Method for creating IonFactoryBuilder initialized with settings to create binary (not textual) writers.
/** * Method for creating {@link IonFactoryBuilder} initialized with settings to * create binary (not textual) writers. */
public static IonFactoryBuilder builderForBinaryWriters() { return new IonFactoryBuilder(true); }
Method for creating IonFactoryBuilder initialized with settings to create textual (not binary) writers.
/** * Method for creating {@link IonFactoryBuilder} initialized with settings to * create textual (not binary) writers. */
public static IonFactoryBuilder builderForTextualWriters() { return new IonFactoryBuilder(false); } @Override public IonFactory copy() { _checkInvalidCopy(IonFactory.class); // note: as with base class, must NOT copy mapper reference return new IonFactory(this, null); } @Override public Version version() { return PackageVersion.VERSION; } @Override public String getFormatName() { return FORMAT_NAME_ION; } public void setCreateBinaryWriters(boolean b) { _cfgCreateBinaryWriters = b; } public boolean createBinaryWriters() { return _cfgCreateBinaryWriters; } @Override // since 2.3 public boolean canHandleBinaryNatively() { // 21-Feb-2017, tatu: I think only support with binary backend return _cfgCreateBinaryWriters; } @Override // since 2.4 public boolean canUseCharArrays() { return false; } /* /********************************************************** /* Configuration, parser settings /********************************************************** */
Method for enabling or disabling specified parser feature (check Feature for list of features)
/** * Method for enabling or disabling specified parser feature * (check {@link IonParser.Feature} for list of features) */
public final IonFactory configure(IonParser.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; }
Method for enabling specified parser feature (check Feature for list of features)
/** * Method for enabling specified parser feature * (check {@link IonParser.Feature} for list of features) */
public IonFactory enable(IonParser.Feature f) { _ionParserFeatures |= f.getMask(); return this; }
Method for disabling specified parser features (check Feature for list of features)
/** * Method for disabling specified parser features * (check {@link IonParser.Feature} for list of features) */
public IonFactory disable(IonParser.Feature f) { _ionParserFeatures &= ~f.getMask(); return this; }
Checked whether specified parser feature is enabled.
/** * Checked whether specified parser feature is enabled. */
public final boolean isEnabled(IonParser.Feature f) { return (_ionParserFeatures & f.getMask()) != 0; } @Override public int getFormatParserFeatures() { return _ionParserFeatures; } /* /********************************************************** /* Configuration, generator settings /********************************************************** */
Method for enabling or disabling specified generator feature (check Feature for list of features)
/** * Method for enabling or disabling specified generator feature * (check {@link IonGenerator.Feature} for list of features) */
public final IonFactory configure(IonGenerator.Feature f, boolean state) { if (state) { enable(f); } else { disable(f); } return this; }
Method for enabling specified generator features (check Feature for list of features)
/** * Method for enabling specified generator features * (check {@link IonGenerator.Feature} for list of features) */
public IonFactory enable(IonGenerator.Feature f) { _ionGeneratorFeatures |= f.getMask(); return this; }
Method for disabling specified generator feature (check Feature for list of features)
/** * Method for disabling specified generator feature * (check {@link IonGenerator.Feature} for list of features) */
public IonFactory disable(IonGenerator.Feature f) { _ionGeneratorFeatures &= ~f.getMask(); return this; }
Check whether specified generator feature is enabled.
/** * Check whether specified generator feature is enabled. */
public final boolean isEnabled(IonGenerator.Feature f) { return (_ionGeneratorFeatures & f.getMask()) != 0; } @Override public int getFormatGeneratorFeatures() { return _ionGeneratorFeatures; } /* *************************************************************** * Extended API *************************************************************** */
Since:2.7
/** * @since 2.7 */
public IonParser createParser(IonReader in) { return new IonParser(in, _system, _createContext(_createContentReference(in), false), getCodec(), _ionParserFeatures); }
Since:2.7
/** * @since 2.7 */
public IonParser createParser(IonValue value) { IonReader in = value.getSystem().newReader(value); return new IonParser(in, _system, _createContext(_createContentReference(in), true), getCodec(), _ionParserFeatures); } // NOTE! Suboptimal return type -- but can't change safely before 3.0 as return // type is part of signature
Since:2.7
/** * @since 2.7 */
public JsonGenerator createGenerator(IonWriter out) { return _createGenerator(out, false, _createContext(_createContentReference(out), false), out); } // actually added in 2.10.5 / 2.11.1 but officially part of 2.12 API
Since:2.12
/** * @since 2.12 */
public IonSystem getIonSystem() { return _system; }
Deprecated:Since 2.7
/** * @deprecated Since 2.7 */
@Deprecated public IonParser createJsonParser(IonReader in) { return createParser(in); }
Deprecated:Since 2.7
/** * @deprecated Since 2.7 */
@Deprecated public IonParser createJsonParser(IonValue value) { return createParser(value); }
Deprecated:Since 2.7
/** * @deprecated Since 2.7 */
@Deprecated public JsonGenerator createJsonGenerator(IonWriter out) { return createGenerator(out); } /* *************************************************************** * Overridden factory methods *************************************************************** */ @Override protected JsonParser _createParser(InputStream in, IOContext ctxt) throws IOException { IonReader ion = _system.newReader(in); return new IonParser(ion, _system, ctxt, getCodec(), _ionParserFeatures); } @Override protected JsonParser _createParser(Reader r, IOContext ctxt) throws IOException { return new IonParser(_system.newReader(r), _system, ctxt, getCodec(), _ionParserFeatures); } @Override protected JsonParser _createParser(char[] data, int offset, int len, IOContext ctxt, boolean recyclable) throws IOException { return _createParser(new CharArrayReader(data, offset, len), ctxt); } @Override protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException { return new IonParser(_system.newReader(data, offset, len), _system, ctxt, getCodec(), _ionParserFeatures); } @Override public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { return _createGenerator(out, enc, false); } @Override public JsonGenerator createGenerator(Writer out) throws IOException { // First things first: no binary writer for Writers: if (createBinaryWriters()) { throw new IOException("Can only create binary Ion writers that output to OutputStream, not Writer"); } return _createGenerator(_system.newTextWriter(out), true, _createContext(_createContentReference(out), false), out); } @Override public JsonGenerator createGenerator(File f, JsonEncoding enc) throws IOException { return _createGenerator(new FileOutputStream(f), enc, true); } /* /*************************************************************** /* Helper methods /*************************************************************** */ @Deprecated protected String _readAll(Reader r, IOContext ctxt) throws IOException { // Let's use Jackson's efficient aggregators... better than JDK defaults TextBuffer tb = ctxt.constructTextBuffer(); char[] buf = tb.emptyAndGetCurrentSegment(); // this gets bit ugly. Blah. int offset = 0; main_loop: while (true) { while (offset < buf.length) { int count = r.read(buf, offset, buf.length - offset); if (count < 0) { break main_loop; } offset += count; } // got full buffer; get another one buf = tb.finishCurrentSegment(); offset = 0; } // Ok, last one is incomplete... tb.setCurrentLength(offset); String result = tb.contentsAsString(); tb.releaseBuffers(); return result; } protected IonGenerator _createGenerator(OutputStream out, JsonEncoding enc, boolean isManaged) throws IOException { IonWriter ion; IOContext ctxt = _createContext(_createContentReference(out), isManaged); Closeable dst; // not necessarily same as 'out'... // Binary writers are simpler: no alternate encodings if (createBinaryWriters()) { ctxt.setEncoding(enc); ion = _system.newBinaryWriter(out); dst = out; } else { if (enc != JsonEncoding.UTF8) { // not sure if non-UTF-8 encodings would be legal... throw new IOException("Ion only supports UTF-8 encoding, can not use "+enc); } // In theory Ion package could take some advantage of getting OutputStream. // In practice we seem to be better off using Jackson's efficient buffering encoder ctxt.setEncoding(enc); Writer w = new UTF8Writer(ctxt, out); ion = _system.newTextWriter(w); dst = w; } return _createGenerator(ion, true, ctxt, dst); } protected IonGenerator _createGenerator(IonWriter ion, boolean ionWriterIsManaged, IOContext ctxt, Closeable dst) { return new IonGenerator(_generatorFeatures, _ionGeneratorFeatures, _objectCodec, ion, ionWriterIsManaged, ctxt, dst); } }