001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.marshall.stream;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.io.*;
022import java.lang.reflect.*;
023
024import org.apache.juneau.marshall.*;
025import org.apache.juneau.marshall.parser.*;
026
027/**
028 * Public low-level pull-parser cursor over a Juneau-formatted document.
029 *
030 * <p>
031 * A StAX-like enum cursor that emits a stream of {@link TokenType} events without materializing
032 * the whole object graph.  This is a format-neutral surface; the same cursor methods work across
033 * every Juneau format that implements {@link TokenReadable} (the structural-token role).
034 *
035 * <h5 class='section'>Usage:</h5>
036 * <p class='bjava'>
037 *    <jc>// Tokenize a JSON document without materializing it.</jc>
038 *    <jk>try</jk> (TokenReader <jv>r</jv> = Json.<jsf>DEFAULT</jsf>.readTokens(<js>"{\"a\":1,\"b\":[true,null]}"</js>)) {
039 *       <jk>while</jk> (<jv>r</jv>.next() != TokenType.<jsf>END_OF_STREAM</jsf>) {
040 *          <jk>switch</jk> (<jv>r</jv>.getCurrentToken()) {
041 *             <jk>case</jk> <jsf>FIELD_NAME</jsf>   -&gt; handleKey(<jv>r</jv>.getFieldName());
042 *             <jk>case</jk> <jsf>VALUE_STRING</jsf> -&gt; handleString(<jv>r</jv>.getString());
043 *             <jk>case</jk> <jsf>VALUE_NUMBER</jsf> -&gt; handleNumber(<jv>r</jv>.getNumber());
044 *             <jk>default</jk> -&gt; { <jc>// structural </jc>}
045 *          }
046 *       }
047 *    }
048 * </p>
049 *
050 * <h5 class='section'>Contract:</h5>
051 * <ul>
052 *    <li>The cursor is <b>purely structural</b>.  It bypasses object swaps and {@code @Schema}
053 *       annotations &mdash; that is the role of the POJO databind path on
054 *       {@link Parser Parser} and its bridges.
055 *    <li>For numeric values both the original lexeme and a parsed {@link Number} are available
056 *       (see {@link #getNumberLexeme()} and {@link #getNumber()}); precision-sensitive
057 *       consumers should prefer the lexeme.
058 *    <li>Concrete implementations are not required to be thread-safe.
059 * </ul>
060 *
061 * <h5 class='section'>See Also:</h5><ul>
062 *    <li>{@link TokenWriter} &mdash; the push-side counterpart.
063 *    <li>{@link TokenType} &mdash; the format-neutral token vocabulary.
064 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a>
065 * </ul>
066 */
067public interface TokenReader extends RecordReader {
068
069   /**
070    * Canonical message thrown as an {@link IllegalStateException} when {@link #read(Class)} is
071    * called while the cursor is not positioned at a value boundary.
072    *
073    * <p>
074    * Shared across all formats so the positioning/error contract is uniform (see the
075    * <c>read</c> contract); implementations throw <c><jk>new</jk> IllegalStateException(
076    * {@link #MSG_READ_NON_VALUE_STATE})</c> rather than inventing their own wording.
077    */
078   String MSG_READ_NON_VALUE_STATE =
079      "read called from a non-value cursor state.  The cursor must be positioned such that next() "
080      + "would emit START_OBJECT / START_ARRAY / VALUE_*; the current state would emit a structural "
081      + "separator, field name, end-container, or end-of-stream instead.";
082
083   /**
084    * Advances the cursor to the next token.
085    *
086    * @return The token type of the new current token, or {@link TokenType#END_OF_STREAM} when
087    *    the underlying input is exhausted.  Never returns {@link TokenType#NOT_AVAILABLE} &mdash;
088    *    that value is reserved for the initial pre-{@code next()} state.
089    * @throws IOException If a problem occurred reading from the underlying stream.
090    * @throws ParseException If the input is malformed for the format.
091    */
092   TokenType next() throws IOException, ParseException;
093
094   /**
095    * Returns the current token type without advancing.
096    *
097    * @return The current token type.  Returns {@link TokenType#NOT_AVAILABLE} before the first
098    *    call to {@link #next()}, and {@link TokenType#END_OF_STREAM} once the stream is exhausted.
099    */
100   TokenType getCurrentToken();
101
102   /**
103    * Returns the current depth of the cursor.
104    *
105    * <p>
106    * Depth starts at <c>0</c> at the document root and increases by 1 for each
107    * {@link TokenType#START_OBJECT} / {@link TokenType#START_ARRAY} encountered (and decreases on
108    * the matching end tokens).
109    *
110    * @return The current depth.
111    */
112   int getDepth();
113
114   /**
115    * Returns the field name when the current token is {@link TokenType#FIELD_NAME}.
116    *
117    * @return The field name.
118    * @throws IllegalStateException If the current token is not {@link TokenType#FIELD_NAME}.
119    */
120   String getFieldName();
121
122   /**
123    * Returns the current scalar value as a string.
124    *
125    * <p>
126    * Defined for {@link TokenType#VALUE_STRING} (the natural value), {@link TokenType#FIELD_NAME}
127    * (returns the field name), {@link TokenType#VALUE_NUMBER} (returns the lexeme), and
128    * {@link TokenType#VALUE_BOOLEAN} (returns <js>"true"</js>/<js>"false"</js>).  For
129    * {@link TokenType#VALUE_NULL} returns <jk>null</jk>.
130    *
131    * @return The string view of the current value.
132    * @throws IllegalStateException If the current token has no string view.
133    */
134   String getString();
135
136   /**
137    * Returns the current numeric value as a parsed {@link Number}.
138    *
139    * <p>
140    * Implementations may parse lazily; the returned {@link Number} subtype is implementation- and
141    * format-defined (e.g. {@link Long} / {@link Double} / {@link java.math.BigDecimal}).  Use
142    * {@link #getNumberLexeme()} to recover the original textual form.
143    *
144    * @return The parsed numeric value.
145    * @throws IllegalStateException If the current token is not {@link TokenType#VALUE_NUMBER}.
146    * @throws ParseException If the lexeme cannot be parsed.
147    */
148   Number getNumber() throws ParseException;
149
150   /**
151    * Returns the original numeric lexeme for the current numeric token.
152    *
153    * <p>
154    * For text formats this is the exact substring that produced the number.  For binary formats
155    * the implementation returns a canonical text rendering of the native numeric token.
156    *
157    * @return The numeric lexeme.
158    * @throws IllegalStateException If the current token is not {@link TokenType#VALUE_NUMBER}.
159    */
160   String getNumberLexeme();
161
162   /**
163    * Returns the current boolean value.
164    *
165    * @return The boolean value.
166    * @throws IllegalStateException If the current token is not {@link TokenType#VALUE_BOOLEAN}.
167    */
168   boolean getBool();
169
170   /**
171    * Returns the current binary value.
172    *
173    * <p>
174    * Binary scalars come from binary formats only (cbor, msgpack, bson, ...).  Text formats
175    * deliver embedded binary content as base64-encoded {@link TokenType#VALUE_STRING}.
176    *
177    * @return The binary value.
178    * @throws IllegalStateException If the current token is not {@link TokenType#VALUE_BINARY}.
179    */
180   byte[] getBinary();
181
182   /**
183    * Returns <jk>true</jk> if {@link #read(Class)} is currently callable on this cursor &mdash;
184    * i.e. the cursor is positioned at a value boundary.
185    *
186    * <p>
187    * This is the natural loop predicate when streaming records:
188    * <p class='bjava'>
189    *    <jk>try</jk> (TokenReader <jv>r</jv> = Json.<jsf>DEFAULT</jsf>.readTokens(<jv>input</jv>)) {
190    *       <jv>r</jv>.next();  <jc>// consume the opening [ </jc>
191    *       <jk>while</jk> (<jv>r</jv>.canRead()) {
192    *          Item <jv>item</jv> = <jv>r</jv>.read(Item.<jk>class</jk>);
193    *          process(<jv>item</jv>);
194    *       }
195    *       <jv>r</jv>.next();  <jc>// consume the closing ]</jc>
196    *    }
197    * </p>
198    *
199    * @return <jk>true</jk> if the next operation can be {@code read}; <jk>false</jk> if the
200    *    cursor is positioned at a structural separator, field name, end-container, or end-of-stream.
201    * @throws IOException If a problem occurred peeking at the underlying stream.
202    * @throws ParseException If the input is malformed for the format.
203    */
204   default boolean canRead() throws IOException, ParseException {
205      return false;
206   }
207
208   /**
209    * Consumes the upcoming value (object, array, or scalar) and binds it to a POJO via the
210    * format's existing parser.
211    *
212    * <p>
213    * <b>Cursor positioning:</b> the cursor must be in a state where the next call to {@link #next()}
214    * would emit a value-shaped token (i.e. {@link TokenType#START_OBJECT}, {@link TokenType#START_ARRAY},
215    * or one of the {@code VALUE_*} tokens).  Calling {@code read} consumes that upcoming value
216    * wholesale and advances the cursor's depth back to where it was before the value would have
217    * started &mdash; structurally equivalent to calling {@link #next()} on a scalar, or
218    * {@link #next()} + {@link #skipChildren()} on a container.
219    *
220    * <p>
221    * <b>Do NOT call {@link #next()} before {@code read}.</b>  Once the structural opener
222    * (e.g. <c>{</c> or <c>[</c>) has been consumed by {@link #next()}, the underlying parser cannot
223    * re-bind the value.  The contract is "instead-of-next, not after-next."
224    *
225    * <p>
226    * <b>Default behavior:</b> the default implementation throws
227    * {@link UnsupportedOperationException}.  Format-specific token readers override this by
228    * delegating to their existing {@code *ParserSession} at the cursor's current input position
229    * and resyncing the cursor's state machine afterward.
230    *
231    * @param <T> The expected return type.
232    * @param type The target Java type.
233    * @return The bound POJO.
234    * @throws IOException If a problem occurred reading from the underlying stream.
235    * @throws ParseException If the input is malformed for the format or cannot be bound to the type.
236    * @throws IllegalStateException If the cursor is not positioned at a value boundary.
237    * @throws UnsupportedOperationException If this format's reader has not implemented the bridge
238    *    (e.g. writer-only formats with no parser, or formats whose Phase-2 increment did not include
239    *    the bridge).
240    */
241   default <T> T read(Class<T> type) throws IOException, ParseException {
242      throw new UnsupportedOperationException(
243         "read is not implemented for " + getClass().getName());
244   }
245
246   /**
247    * Same as {@link #read(Class)} but accepts a pre-resolved {@link ClassMeta}.
248    *
249    * @param <T> The expected return type.
250    * @param type The target type.
251    * @return The bound POJO.
252    * @throws IOException If a problem occurred reading from the underlying stream.
253    * @throws ParseException If the input is malformed or cannot be bound to the type.
254    */
255   default <T> T read(ClassMeta<T> type) throws IOException, ParseException {
256      throw new UnsupportedOperationException(
257         "read is not implemented for " + getClass().getName());
258   }
259
260   /**
261    * Same as {@link #read(Class)} but accepts a parameterized {@link Type} and optional type
262    * arguments (the same shape as {@link Parser#read(Object, Type, Type...)}).
263    *
264    * @param <T> The expected return type.
265    * @param type The target type.
266    * @param args Optional type arguments for parameterized types.
267    * @return The bound POJO.
268    * @throws IOException If a problem occurred reading from the underlying stream.
269    * @throws ParseException If the input is malformed or cannot be bound to the type.
270    */
271   default <T> T read(Type type, Type... args) throws IOException, ParseException {
272      throw new UnsupportedOperationException(
273         "read is not implemented for " + getClass().getName());
274   }
275
276   /**
277    * Skips over the children of the current structural token.
278    *
279    * <p>
280    * If the current token is {@link TokenType#START_OBJECT} or {@link TokenType#START_ARRAY},
281    * the cursor is advanced to the matching {@link TokenType#END_OBJECT} or
282    * {@link TokenType#END_ARRAY} (i.e. the entire sub-tree is consumed).  For any other token this
283    * is a no-op.
284    *
285    * @throws IOException If a problem occurred reading from the underlying stream.
286    * @throws ParseException If the input is malformed for the format.
287    */
288   void skipChildren() throws IOException, ParseException;
289
290   /**
291    * Structural token cursors are always O(1)-memory streamers.
292    *
293    * @return Always <jk>true</jk>.
294    */
295   @Override
296   default boolean isStreaming() { return true; }
297
298   /**
299    * Closes the underlying stream.
300    *
301    * <p>
302    * Implementations should be idempotent &mdash; closing a closed reader is a no-op.
303    */
304   @Override
305   void close() throws IOException;
306
307   // =================================================================================
308   // Binary-native opt-in metadata accessors.  Default cursors and formats without
309   // native concepts inherit the safe defaults below: getNativeKind() returns NONE,
310   // getTagCount() returns 0, and the value accessors throw.  Format-specific cursors
311   // override the relevant subset (CBOR overrides getNativeKind/getTagCount/getTag/
312   // getSimpleValue; MsgPack overrides getNativeKind/getExtType).  See
313   // {@link BinaryNativeKind} for the catalog of native concepts.
314   // =================================================================================
315
316   /**
317    * Returns the binary-native classification of the current token.
318    *
319    * @return The native kind, or {@link BinaryNativeKind#NONE NONE} when the current token
320    *    carries no binary-native metadata.  Never {@code null}.
321    */
322   default BinaryNativeKind getNativeKind() {
323      return BinaryNativeKind.NONE;
324   }
325
326   /**
327    * Returns the number of semantic tags wrapping the current token.
328    *
329    * @return The tag count (0 when {@link #getNativeKind()} is not
330    *    {@link BinaryNativeKind#CBOR_TAG CBOR_TAG}).
331    */
332   default int getTagCount() {
333      return 0;
334   }
335
336   /**
337    * Returns the semantic tag at the specified position in the tag stack.
338    *
339    * @param index The tag position; outermost tag is {@code 0}.
340    * @return The tag number.
341    * @throws IndexOutOfBoundsException If {@code index} is outside {@code [0, getTagCount())}.
342    */
343   default long getTag(int index) {
344      throw new IndexOutOfBoundsException("Tag index " + index + " out of bounds for tagCount " + getTagCount());
345   }
346
347   /**
348    * Returns the typed-binary type byte for the current token.
349    *
350    * @return The signed type byte (range {@code -128..127}).
351    * @throws IllegalStateException If {@link #getNativeKind()} is not
352    *    {@link BinaryNativeKind#MSGPACK_EXT MSGPACK_EXT}.
353    */
354   default int getExtType() {
355      throw isex("Current token is not a typed-binary (ext) value (nativeKind=%s)", getNativeKind());
356   }
357
358   /**
359    * Returns the opaque simple value for the current token.
360    *
361    * @return The simple int.
362    * @throws IllegalStateException If {@link #getNativeKind()} is not
363    *    {@link BinaryNativeKind#CBOR_SIMPLE CBOR_SIMPLE}.
364    */
365   default int getSimpleValue() {
366      throw isex("Current token is not a simple value (nativeKind=%s)", getNativeKind());
367   }
368}