package com.fasterxml.jackson.core.json; import com.fasterxml.jackson.core.*; /** * Extension of {@link JsonStreamContext}, which implements * core methods needed, and also exposes * more complete API to generator implementation classes. */ public class JsonWriteContext extends JsonStreamContext { // // // Return values for writeValue() public final static int STATUS_OK_AS_IS = 0; public final static int STATUS_OK_AFTER_COMMA = 1; public final static int STATUS_OK_AFTER_COLON = 2; public final static int STATUS_OK_AFTER_SPACE = 3; // in root context public final static int STATUS_EXPECT_VALUE = 4; public final static int STATUS_EXPECT_NAME = 5; protected final JsonWriteContext _parent; /** * Name of the field of which value is to be parsed; only * used for OBJECT contexts */ protected String _currentName; /* /********************************************************** /* Simple instance reuse slots; speed up things /* a bit (10-15%) for docs with lots of small /* arrays/objects /********************************************************** */ protected JsonWriteContext _child = null; /* /********************************************************** /* Life-cycle /********************************************************** */ protected JsonWriteContext(int type, JsonWriteContext parent) { super(); _type = type; _parent = parent; _index = -1; } // // // Factory methods public static JsonWriteContext createRootContext() { return new JsonWriteContext(TYPE_ROOT, null); } private JsonWriteContext reset(int type) { _type = type; _index = -1; _currentName = null; return this; } public final JsonWriteContext createChildArrayContext() { JsonWriteContext ctxt = _child; if (ctxt == null) { _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this); return ctxt; } return ctxt.reset(TYPE_ARRAY); } public final JsonWriteContext createChildObjectContext() { JsonWriteContext ctxt = _child; if (ctxt == null) { _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this); return ctxt; } return ctxt.reset(TYPE_OBJECT); } // // // Shared API @Override public final JsonWriteContext getParent() { return _parent; } @Override public final String getCurrentName() { return _currentName; } // // // API sub-classes are to implement /** * Method that writer is to call before it writes a field name. * * @return Index of the field entry (0-based) */ public final int writeFieldName(String name) { if (_type == TYPE_OBJECT) { if (_currentName != null) { // just wrote a name... return STATUS_EXPECT_VALUE; } _currentName = name; return (_index < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA; } return STATUS_EXPECT_VALUE; } public final int writeValue() { // Most likely, object: if (_type == TYPE_OBJECT) { if (_currentName == null) { return STATUS_EXPECT_NAME; } _currentName = null; ++_index; return STATUS_OK_AFTER_COLON; } // Ok, array? if (_type == TYPE_ARRAY) { int ix = _index; ++_index; return (ix < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA; } // Nope, root context // No commas within root context, but need space ++_index; return (_index == 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_SPACE; } // // // Internally used abstract methods protected final void appendDesc(StringBuilder sb) { if (_type == TYPE_OBJECT) { sb.append('{'); if (_currentName != null) { sb.append('"'); // !!! TODO: Name chars should be escaped? sb.append(_currentName); sb.append('"'); } else { sb.append('?'); } sb.append('}'); } else if (_type == TYPE_ARRAY) { sb.append('['); sb.append(getCurrentIndex()); sb.append(']'); } else { // nah, ROOT: sb.append("/"); } } // // // Overridden standard methods /** * Overridden to provide developer writeable "JsonPath" representation * of the context. */ @Override public final String toString() { StringBuilder sb = new StringBuilder(64); appendDesc(sb); return sb.toString(); } }