src.org.codehaus.jackson.impl.JsonGeneratorBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of worldwindx Show documentation
Show all versions of worldwindx Show documentation
World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.
package org.codehaus.jackson.impl;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.codehaus.jackson.*;
/**
* This base class implements part of API that a JSON generator exposes
* to applications, adds shared internal methods that sub-classes
* can use and adds some abstract methods sub-classes must implement.
*/
public abstract class JsonGeneratorBase
extends JsonGenerator
{
/*
////////////////////////////////////////////////////
// Configuration
////////////////////////////////////////////////////
*/
protected ObjectCodec _objectCodec;
/**
* Bit flag composed of bits that indicate which
* {@link org.codehaus.jackson.JsonGenerator.Feature}s
* are enabled.
*/
protected int _features;
/**
* Flag set to indicate that implicit conversion from number
* to JSON String is needed (as per
* {@link org.codehaus.jackson.JsonGenerator.Feature#WRITE_NUMBERS_AS_STRINGS}).
*/
protected boolean _cfgNumbersAsStrings;
/*
////////////////////////////////////////////////////
// State
////////////////////////////////////////////////////
*/
/**
* Object that keeps track of the current contextual state
* of the generator.
*/
protected JsonWriteContext _writeContext;
/**
* Flag that indicates whether generator is closed or not. Gets
* set when it is closed by an explicit call
* ({@link #close}).
*/
protected boolean _closed;
/*
////////////////////////////////////////////////////
// Life-cycle
////////////////////////////////////////////////////
*/
protected JsonGeneratorBase(int features, ObjectCodec codec)
{
super();
_features = features;
_writeContext = JsonWriteContext.createRootContext();
_objectCodec = codec;
_cfgNumbersAsStrings = isEnabled(Feature.WRITE_NUMBERS_AS_STRINGS);
}
/*
////////////////////////////////////////////////////
// Configuration
////////////////////////////////////////////////////
*/
@Override
public JsonGenerator enable(Feature f) {
_features |= f.getMask();
if (f == Feature.WRITE_NUMBERS_AS_STRINGS) {
_cfgNumbersAsStrings = true;
}
return this;
}
@Override
public JsonGenerator disable(Feature f) {
_features &= ~f.getMask();
if (f == Feature.WRITE_NUMBERS_AS_STRINGS) {
_cfgNumbersAsStrings = false;
}
return this;
}
//public JsonGenerator configure(Feature f, boolean state) { }
@Override
public final boolean isEnabled(Feature f) {
return (_features & f.getMask()) != 0;
}
public final JsonGenerator useDefaultPrettyPrinter()
{
return setPrettyPrinter(new DefaultPrettyPrinter());
}
public final JsonGenerator setCodec(ObjectCodec oc) {
_objectCodec = oc;
return this;
}
public final ObjectCodec getCodec() { return _objectCodec; }
/*
////////////////////////////////////////////////////
// Public API, accessors
////////////////////////////////////////////////////
*/
/**
* Note: co-variant return type.
*/
public final JsonWriteContext getOutputContext() { return _writeContext; }
/*
////////////////////////////////////////////////////
// Public API, write methods, structural
////////////////////////////////////////////////////
*/
public final void writeStartArray()
throws IOException, JsonGenerationException
{
// Array is a value, need to verify it's allowed
_verifyValueWrite("start an array");
_writeContext = _writeContext.createChildArrayContext();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartArray(this);
} else {
_writeStartArray();
}
}
protected abstract void _writeStartArray()
throws IOException, JsonGenerationException;
public final void writeEndArray()
throws IOException, JsonGenerationException
{
if (!_writeContext.inArray()) {
_reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc());
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
} else {
_writeEndArray();
}
_writeContext = _writeContext.getParent();
}
protected abstract void _writeEndArray()
throws IOException, JsonGenerationException;
public final void writeStartObject()
throws IOException, JsonGenerationException
{
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartObject(this);
} else {
_writeStartObject();
}
}
protected abstract void _writeStartObject()
throws IOException, JsonGenerationException;
public final void writeEndObject()
throws IOException, JsonGenerationException
{
if (!_writeContext.inObject()) {
_reportError("Current context not an object but "+_writeContext.getTypeDesc());
}
_writeContext = _writeContext.getParent();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
} else {
_writeEndObject();
}
}
protected abstract void _writeEndObject()
throws IOException, JsonGenerationException;
public final void writeFieldName(String name)
throws IOException, JsonGenerationException
{
// Object is a value, need to verify it's allowed
int status = _writeContext.writeFieldName(name);
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
_writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
}
protected abstract void _writeFieldName(String name, boolean commaBefore)
throws IOException, JsonGenerationException;
/*
////////////////////////////////////////////////////
// Public API, write methods, textual
////////////////////////////////////////////////////
*/
//public abstract void writeString(String text) throws IOException, JsonGenerationException;
//public abstract void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException;
//public abstract void writeRaw(String text) throws IOException, JsonGenerationException;
//public abstract void writeRaw(char[] text, int offset, int len) throws IOException, JsonGenerationException;
//public abstract void writeBinary(byte[] data, int offset, int len, boolean includeLFs) throws IOException, JsonGenerationException;
/*
////////////////////////////////////////////////////
// Public API, write methods, primitive
////////////////////////////////////////////////////
*/
public abstract void writeNumber(int i)
throws IOException, JsonGenerationException;
public abstract void writeNumber(long l)
throws IOException, JsonGenerationException;
public abstract void writeNumber(double d)
throws IOException, JsonGenerationException;
public abstract void writeNumber(float f)
throws IOException, JsonGenerationException;
public abstract void writeNumber(BigDecimal dec)
throws IOException, JsonGenerationException;
public abstract void writeBoolean(boolean state)
throws IOException, JsonGenerationException;
public abstract void writeNull()
throws IOException, JsonGenerationException;
/*
////////////////////////////////////////////////////
// Public API, write methods, POJOs, trees
////////////////////////////////////////////////////
*/
public void writeObject(Object value)
throws IOException, JsonProcessingException
{
if (value == null) {
// important: call method that does check value write:
writeNull();
} else {
/* 02-Mar-2009, tatu: we are NOT to call _verifyValueWrite here,
* because that will be done when codec actually serializes
* contained POJO. If we did call it it would advance state
* causing exception later on
*/
if (_objectCodec != null) {
_objectCodec.writeValue(this, value);
return;
}
_writeSimpleObject(value);
}
}
public void writeTree(JsonNode rootNode)
throws IOException, JsonProcessingException
{
// As with 'writeObject()', we are not check if write would work
if (rootNode == null) {
writeNull();
} else {
if (_objectCodec == null) {
throw new IllegalStateException("No ObjectCodec defined for the generator, can not serialize JsonNode-based trees");
}
_objectCodec.writeTree(this, rootNode);
}
}
/*
////////////////////////////////////////////////////
// Public API, low-level output handling
////////////////////////////////////////////////////
*/
public abstract void flush() throws IOException;
public void close() throws IOException
{
_closed = true;
}
public boolean isClosed() { return _closed; }
/*
////////////////////////////////////////////////////
// Public API, copy-through methods
////////////////////////////////////////////////////
*/
public final void copyCurrentEvent(JsonParser jp)
throws IOException, JsonProcessingException
{
switch(jp.getCurrentToken()) {
case START_OBJECT:
writeStartObject();
break;
case END_OBJECT:
writeEndObject();
break;
case START_ARRAY:
writeStartArray();
break;
case END_ARRAY:
writeEndArray();
break;
case FIELD_NAME:
writeFieldName(jp.getCurrentName());
break;
case VALUE_STRING:
writeString(jp.getTextCharacters(), jp.getTextOffset(), jp.getTextLength());
break;
case VALUE_NUMBER_INT:
switch (jp.getNumberType()) {
case INT:
writeNumber(jp.getIntValue());
break;
case BIG_INTEGER:
writeNumber(jp.getBigIntegerValue());
break;
default:
writeNumber(jp.getLongValue());
}
break;
case VALUE_NUMBER_FLOAT:
switch (jp.getNumberType()) {
case BIG_DECIMAL:
writeNumber(jp.getDecimalValue());
break;
case FLOAT:
writeNumber(jp.getFloatValue());
break;
default:
writeNumber(jp.getDoubleValue());
}
break;
case VALUE_TRUE:
writeBoolean(true);
break;
case VALUE_FALSE:
writeBoolean(false);
break;
case VALUE_NULL:
writeNull();
break;
case VALUE_EMBEDDED_OBJECT:
writeObject(jp.getEmbeddedObject());
break;
default:
_cantHappen();
}
}
public final void copyCurrentStructure(JsonParser jp)
throws IOException, JsonProcessingException
{
JsonToken t = jp.getCurrentToken();
// Let's handle field-name separately first
if (t == JsonToken.FIELD_NAME) {
writeFieldName(jp.getCurrentName());
t = jp.nextToken();
// fall-through to copy the associated value
}
switch (t) {
case START_ARRAY:
writeStartArray();
while (jp.nextToken() != JsonToken.END_ARRAY) {
copyCurrentStructure(jp);
}
writeEndArray();
break;
case START_OBJECT:
writeStartObject();
while (jp.nextToken() != JsonToken.END_OBJECT) {
copyCurrentStructure(jp);
}
writeEndObject();
break;
default: // others are simple:
copyCurrentEvent(jp);
}
}
/*
////////////////////////////////////////////////////
// Package methods for this, sub-classes
////////////////////////////////////////////////////
*/
protected abstract void _releaseBuffers();
protected abstract void _verifyValueWrite(String typeMsg)
throws IOException, JsonGenerationException;
protected void _reportError(String msg)
throws JsonGenerationException
{
throw new JsonGenerationException(msg);
}
protected void _cantHappen()
{
throw new RuntimeException("Internal error: should never end up through this code path");
}
/**
* Helper method to try to call appropriate write method for given
* untyped Object. At this point, no structural conversions should be done,
* only simple basic types are to be coerced as necessary.
*
* @param value Non-null value to write
*/
protected void _writeSimpleObject(Object value)
throws IOException, JsonGenerationException
{
/* 31-Dec-2009, tatu: Actually, we could just handle some basic
* types even without codec. This can improve interoperability,
* and specifically help with TokenBuffer.
*/
if (value == null) {
writeNull();
return;
}
if (value instanceof String) {
writeString((String) value);
return;
}
if (value instanceof Number) {
Number n = (Number) value;
if (n instanceof Integer) {
writeNumber(n.intValue());
return;
} else if (n instanceof Long) {
writeNumber(n.longValue());
return;
} else if (n instanceof Double) {
writeNumber(n.doubleValue());
return;
} else if (n instanceof Float) {
writeNumber(n.floatValue());
return;
} else if (n instanceof Short) {
writeNumber(n.shortValue());
return;
} else if (n instanceof Byte) {
writeNumber(n.byteValue());
return;
} else if (n instanceof BigInteger) {
writeNumber((BigInteger) n);
return;
} else if (n instanceof BigDecimal) {
writeNumber((BigDecimal) n);
return;
// then Atomic types
} else if (n instanceof AtomicInteger) {
writeNumber(((AtomicInteger) n).get());
return;
} else if (n instanceof AtomicLong) {
writeNumber(((AtomicLong) n).get());
return;
}
} else if (value instanceof byte[]) {
writeBinary((byte[]) value);
return;
} else if (value instanceof Boolean) {
writeBoolean(((Boolean) value).booleanValue());
return;
} else if (value instanceof AtomicBoolean) {
writeBoolean(((AtomicBoolean) value).get());
return;
}
throw new IllegalStateException("No ObjectCodec defined for the generator, can only serialize simple wrapper types (type passed "
+value.getClass().getName()+")");
}
}