1 /* Jackson JSON-processor. 2 * 3 * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi 4 */ 5 6 package com.fasterxml.jackson.core; 7 8 import com.fasterxml.jackson.core.io.CharTypes; 9 10 /** 11 * Shared base class for streaming processing contexts used during 12 * reading and writing of Json content using Streaming API. 13 * This context is also exposed to applications: 14 * context object can be used by applications to get an idea of 15 * relative position of the parser/generator within json content 16 * being processed. This allows for some contextual processing: for 17 * example, output within Array context can differ from that of 18 * Object context. 19 */ 20 public abstract class JsonStreamContext 21 { 22 // // // Type constants used internally 23 24 protected final static int TYPE_ROOT = 0; 25 protected final static int TYPE_ARRAY = 1; 26 protected final static int TYPE_OBJECT = 2; 27 28 protected int _type; 29 30 /** 31 * Index of the currently processed entry. Starts with -1 to signal 32 * that no entries have been started, and gets advanced each 33 * time a new entry is started, either by encountering an expected 34 * separator, or with new values if no separators are expected 35 * (the case for root context). 36 */ 37 protected int _index; 38 39 /* 40 /********************************************************** 41 /* Life-cycle 42 /********************************************************** 43 */ 44 JsonStreamContext()45 protected JsonStreamContext() { } 46 47 /** 48 * Copy constructor used by sub-classes for creating copies for 49 * buffering. 50 * 51 * @since 2.9 52 */ JsonStreamContext(JsonStreamContext base)53 protected JsonStreamContext(JsonStreamContext base) { 54 _type = base._type; 55 _index = base._index; 56 } 57 58 /** 59 * @since 2.9 60 */ JsonStreamContext(int type, int index)61 protected JsonStreamContext(int type, int index) { 62 _type = type; 63 _index = index; 64 } 65 66 /* 67 /********************************************************** 68 /* Public API, accessors 69 /********************************************************** 70 */ 71 72 /** 73 * Accessor for finding parent context of this context; will 74 * return null for root context. 75 */ getParent()76 public abstract JsonStreamContext getParent(); 77 78 /** 79 * Method that returns true if this context is an Array context; 80 * that is, content is being read from or written to a Json Array. 81 */ inArray()82 public final boolean inArray() { return _type == TYPE_ARRAY; } 83 84 /** 85 * Method that returns true if this context is a Root context; 86 * that is, content is being read from or written to without 87 * enclosing array or object structure. 88 */ inRoot()89 public final boolean inRoot() { return _type == TYPE_ROOT; } 90 91 /** 92 * Method that returns true if this context is an Object context; 93 * that is, content is being read from or written to a Json Object. 94 */ inObject()95 public final boolean inObject() { return _type == TYPE_OBJECT; } 96 97 /** 98 * Method for accessing simple type description of current context; 99 * either ROOT (for root-level values), OBJECT (for field names and 100 * values of JSON Objects) or ARRAY (for values of JSON Arrays) 101 * 102 * @deprecated Since 2.8 use {@link #typeDesc} instead 103 */ 104 @Deprecated // since 2.8 getTypeDesc()105 public final String getTypeDesc() { 106 switch (_type) { 107 case TYPE_ROOT: return "ROOT"; 108 case TYPE_ARRAY: return "ARRAY"; 109 case TYPE_OBJECT: return "OBJECT"; 110 } 111 return "?"; 112 } 113 114 /** 115 * @since 2.8 116 */ typeDesc()117 public String typeDesc() { 118 switch (_type) { 119 case TYPE_ROOT: return "root"; 120 case TYPE_ARRAY: return "Array"; 121 case TYPE_OBJECT: return "Object"; 122 } 123 return "?"; 124 } 125 126 /** 127 * @return Number of entries that are complete and started. 128 */ getEntryCount()129 public final int getEntryCount() { return _index + 1; } 130 131 /** 132 * @return Index of the currently processed entry, if any 133 */ getCurrentIndex()134 public final int getCurrentIndex() { return (_index < 0) ? 0 : _index; } 135 136 /** 137 * Method that may be called to verify whether this context has valid index: 138 * will return `false` before the first entry of Object context or before 139 * first element of Array context; otherwise returns `true`. 140 * 141 * @since 2.9 142 */ hasCurrentIndex()143 public boolean hasCurrentIndex() { return _index >= 0; } 144 145 /** 146 * Method that may be called to check if this context is either: 147 *<ul> 148 * <li>Object, with at least one entry written (partially or completely) 149 * </li> 150 * <li>Array, with at least one entry written (partially or completely) 151 * </li> 152 *</ul> 153 * and if so, return `true`; otherwise return `false`. Latter case includes 154 * Root context (always), and Object/Array contexts before any entries/elements 155 * have been read or written. 156 *<p> 157 * Method is mostly used to determine whether this context should be used for 158 * constructing {@link JsonPointer} 159 * 160 * @since 2.9 161 */ hasPathSegment()162 public boolean hasPathSegment() { 163 if (_type == TYPE_OBJECT) { 164 return hasCurrentName(); 165 } else if (_type == TYPE_ARRAY) { 166 return hasCurrentIndex(); 167 } 168 return false; 169 } 170 171 /** 172 * Method for accessing name associated with the current location. 173 * Non-null for <code>FIELD_NAME</code> and value events that directly 174 * follow field names; null for root level and array values. 175 */ getCurrentName()176 public abstract String getCurrentName(); 177 178 /** 179 * @since 2.9 180 */ hasCurrentName()181 public boolean hasCurrentName() { return getCurrentName() != null; } 182 183 /** 184 * Method for accessing currently active value being used by data-binding 185 * (as the source of streaming data to write, or destination of data being 186 * read), at this level in hierarchy. 187 *<p> 188 * Note that "current value" is NOT populated (or used) by Streaming parser or generator; 189 * it is only used by higher-level data-binding functionality. 190 * The reason it is included here is that it can be stored and accessed hierarchically, 191 * and gets passed through data-binding. 192 * 193 * @return Currently active value, if one has been assigned. 194 * 195 * @since 2.5 196 */ getCurrentValue()197 public Object getCurrentValue() { 198 return null; 199 } 200 201 /** 202 * Method to call to pass value to be returned via {@link #getCurrentValue}; typically 203 * called indirectly through {@link JsonParser#setCurrentValue} 204 * or {@link JsonGenerator#setCurrentValue}). 205 * 206 * @since 2.5 207 */ setCurrentValue(Object v)208 public void setCurrentValue(Object v) { } 209 210 /** 211 * Factory method for constructing a {@link JsonPointer} that points to the current 212 * location within the stream that this context is for, excluding information about 213 * "root context" (only relevant for multi-root-value cases) 214 * 215 * @since 2.9 216 */ pathAsPointer()217 public JsonPointer pathAsPointer() { 218 return JsonPointer.forPath(this, false); 219 } 220 221 /** 222 * Factory method for constructing a {@link JsonPointer} that points to the current 223 * location within the stream that this context is for, optionally including 224 * "root value index" 225 * 226 * @param includeRoot Whether root-value offset is included as the first segment or not; 227 * 228 * @since 2.9 229 */ pathAsPointer(boolean includeRoot)230 public JsonPointer pathAsPointer(boolean includeRoot) { 231 return JsonPointer.forPath(this, includeRoot); 232 } 233 234 /** 235 * Optional method that may be used to access starting location of this context: 236 * for example, in case of JSON `Object` context, offset at which `[` token was 237 * read or written. Often used for error reporting purposes. 238 * Implementations that do not keep track of such location are expected to return 239 * {@link JsonLocation#NA}; this is what the default implementation does. 240 * 241 * @return Location pointing to the point where the context 242 * start marker was found (or written); never `null`. 243 *<p> 244 * NOTE: demoted from <code>JsonReadContext</code> in 2.9, to allow use for 245 * "non-standard" read contexts. 246 * 247 * @since 2.9 248 */ getStartLocation(Object srcRef)249 public JsonLocation getStartLocation(Object srcRef) { 250 return JsonLocation.NA; 251 } 252 253 /** 254 * Overridden to provide developer readable "JsonPath" representation 255 * of the context. 256 * 257 * @since 2.9 258 */ 259 @Override toString()260 public String toString() { 261 StringBuilder sb = new StringBuilder(64); 262 switch (_type) { 263 case TYPE_ROOT: 264 sb.append("/"); 265 break; 266 case TYPE_ARRAY: 267 sb.append('['); 268 sb.append(getCurrentIndex()); 269 sb.append(']'); 270 break; 271 case TYPE_OBJECT: 272 default: 273 sb.append('{'); 274 String currentName = getCurrentName(); 275 if (currentName != null) { 276 sb.append('"'); 277 CharTypes.appendQuoted(sb, currentName); 278 sb.append('"'); 279 } else { 280 sb.append('?'); 281 } 282 sb.append('}'); 283 break; 284 } 285 return sb.toString(); 286 } 287 } 288