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.json;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020import static org.apache.juneau.commons.utils.SystemUtils.*;
021
022import java.io.*;
023import java.util.*;
024import java.util.concurrent.*;
025
026import org.apache.juneau.commons.bean.*;
027import org.apache.juneau.commons.collections.*;
028import org.apache.juneau.marshall.*;
029import org.apache.juneau.marshall.collections.*;
030import org.apache.juneau.marshall.json5.*;
031import org.apache.juneau.marshall.parser.*;
032import org.apache.juneau.marshall.stream.*;
033
034/**
035 * Parses any valid RFC 8259 JSON text into a POJO model.
036 *
037 * <p>
038 * This parser strictly enforces RFC 8259 JSON syntax. Double-quoted strings only; single-quoted strings,
039 * comments, trailing commas, and unquoted keys are rejected. For JSON5 syntax (single quotes, comments,
040 * etc.), use {@link Json5Parser}.
041 *
042 * <h5 class='topic'>Media types</h5>
043 * <p>
044 * Handles <c>Content-Type</c> types:  <bc>application/json, text/json, application/jcs+json</bc>
045 *
046 * <h5 class='topic'>Description</h5>
047 * <p>
048 * This parser uses a state machine, which makes it very fast and efficient.  It parses JSON in about 70% of the
049 * time that it takes the built-in Java DOM parsers to parse equivalent XML.
050 *
051 * <p>
052 * This parser handles all valid RFC 8259 JSON syntax.
053 *
054 * <p>
055 * Also handles negative, decimal, hexadecimal, octal, and double numbers, including exponential notation.
056 *
057 * <p>
058 * This parser handles the following input, and automatically returns the corresponding Java class.
059 * <ul class='spaced-list'>
060 *    <li>
061 *       JSON objects (<js>"{...}"</js>) are converted to {@link JsonMap JsonMaps}.
062 *       <b>Note:</b>  If a <code><xa>_type</xa>=<xs>'xxx'</xs></code> attribute is specified on the object, then an
063 *       attempt is made to convert the object to an instance of the specified Java bean class.
064 *       See the {@link org.apache.juneau.marshall.MarshallingContext.Builder#typePropertyName(String) MarshallingContext.Builder#typePropertyName(String)} setting for more information about parsing
065 *       beans from JSON.
066 *    <li>
067 *       JSON arrays (<js>"[...]"</js>) are converted to {@link JsonList JsonLists}.
068 *    <li>
069 *       JSON string literals (<js>"\"xyz\""</js>) are converted to {@link String Strings}.
070 *    <li>
071 *       JSON numbers (<js>"123"</js>, including octal/hexadecimal/exponential notation) are converted to
072 *       {@link Integer Integers}, {@link Long Longs}, {@link Float Floats}, or {@link Double Doubles} depending on
073 *       whether the number is decimal, and the size of the number.
074 *    <li>
075 *       JSON booleans (<js>"false"</js>) are converted to {@link Boolean Booleans}.
076 *    <li>
077 *       JSON nulls (<js>"null"</js>) are converted to <jk>null</jk>.
078 * </ul>
079 *
080 * <p>
081 * Input can be any of the following:
082 * <ul class='spaced-list'>
083 *    <li>
084 *       <js>"{...}"</js> - Converted to an {@link JsonMap} or an instance of a Java bean if a <xa>_type</xa>
085 *       attribute is present.
086 *    <li>
087 *       <js>"[...]"</js> - Converted to an {@link JsonList}.
088 *    <li>
089 *       <js>"123..."</js> - Converted to a {@link Number} (either {@link Integer}, {@link Long}, {@link Float},
090 *       or {@link Double}).
091 *    <li>
092 *       <js>"true"</js>/<js>"false"</js> - Converted to a {@link Boolean}.
093 *    <li>
094 *       <js>"null"</js> - Returns <jk>null</jk>.
095 *    <li>
096 *       <js>"\"xxx\""</js> - Converted to a {@link String} (double quotes only).
097 * </ul>
098 *
099 * <p>
100 * TIP:  If you know you're parsing a JSON object or array, it can be easier to parse it using the
101 * {@link JsonMap#JsonMap(CharSequence) JsonMap(CharSequence)} or {@link JsonList#JsonList(CharSequence)
102 * JsonList(CharSequence)} constructors instead of using this class.
103 * The end result should be the same.
104 *
105 * <h5 class='figure'>Example input (Map of name/age):</h5>
106 * <p class='bjson'>
107 *    {<js>"name"</js>:<js>"Alice"</js>,<js>"age"</js>:30}
108 * </p>
109 *
110 * <h5 class='figure'>Complex (nested object + array):</h5>
111 * <p class='bjson'>
112 *    {<js>"name"</js>:<js>"Alice"</js>,<js>"age"</js>:30,<js>"address"</js>:{<js>"street"</js>:<js>"123 Main St"</js>,<js>"city"</js>:<js>"Boston"</js>,<js>"state"</js>:<js>"MA"</js>},<js>"tags"</js>:[<js>"a"</js>,<js>"b"</js>,<js>"c"</js>]}
113 * </p>
114 *
115 * <h5 class='section'>Notes:</h5><ul>
116 *    <li class='note'>This class is thread safe and reusable.
117 * </ul>
118 *
119 * <h5 class='section'>See Also:</h5><ul>
120 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JsonSupport">JSON</a>
121 *    <li class='link'>{@link Json5Parser} - For JSON5 syntax (single quotes, comments, etc.)
122 * </ul>
123 */
124@SuppressWarnings({
125   "java:S110", // Inheritance depth acceptable
126   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
127   "java:S9149", // Per-format static factories intentionally shadow the parent's.
128   "resource" // readTokens(...) returns a Closeable owned by the caller; Eclipse JDT @Owning warning is by design.
129})
130public class JsonParser extends ReaderParser implements JsonMetaProvider, TokenReadable, ArrayRecordReadable {
131
132   /**
133    * Builder class.
134    *
135    * <p>
136    * Unlike the abstract context builders, this builder is concrete <i>and</i> generic: it terminates the CRTP
137    * recursion via the leaf-free {@code new Builder<>()} pattern (see {@link JsonParser#create()} /
138    * {@link JsonParser#copy()}) rather than via a separate concrete {@code DefaultBuilder} leaf.
139    */
140   @SuppressWarnings({
141      "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
142   })
143   public static class Builder<SELF extends Builder<SELF>> extends ReaderParser.Builder<SELF> {
144
145      private static final Cache<HashKey,JsonParser> CACHE = Cache.of(HashKey.class, JsonParser.class).build();
146
147      private boolean validateEnd;
148
149      /**
150       * Constructor, default settings.
151       */
152      protected Builder() {
153         consumes("application/json,text/json,application/jcs+json");
154         validateEnd = env("JsonParser.validateEnd", false);
155      }
156
157      /**
158       * Copy constructor.
159       *
160       * @param copyFrom The builder to copy from.
161       *    <br>Cannot be <jk>null</jk>.
162       */
163      protected Builder(Builder<?> copyFrom) {
164         super(reqnn("copyFrom", copyFrom));
165         validateEnd = copyFrom.validateEnd;
166      }
167
168      /**
169       * Copy constructor.
170       *
171       * @param copyFrom The bean to copy from.
172       *    <br>Cannot be <jk>null</jk>.
173       */
174      protected Builder(JsonParser copyFrom) {
175         super(reqnn("copyFrom", copyFrom));
176         validateEnd = copyFrom.validateEnd;
177      }
178
179      @Override /* Overridden from Context.Builder<?> */
180      public JsonParser build() {
181         return cache(CACHE).build(JsonParser.class);
182      }
183
184      @Override /* Overridden from Context.Builder<?> */
185      @SuppressWarnings({
186         "unchecked" // CRTP self-type cast on the leaf-free Builder copy is safe by construction.
187      })
188      public SELF copy() {
189         return (SELF) new Builder<>(this);
190      }
191
192      @Override /* Overridden from Context.Builder<?> */
193      public HashKey hashKey() {
194         return HashKey.of(super.hashKey(), validateEnd);
195      }
196
197
198      /**
199       * Validate end.
200       *
201       * <p>
202       * When enabled, after parsing a POJO from the input, verifies that the remaining input in
203       * the stream consists of only comments or whitespace.
204       *
205       * <h5 class='section'>Example:</h5>
206       * <p class='bjava'>
207       *    <jc>// Create a parser that validates that there's no garbage at the end of the input.</jc>
208       *    ReaderParser <jv>parser</jv> = JsonParser.
209       *       .<jsm>create</jsm>()
210       *       .validateEnd()
211       *       .build();
212       *
213       *    <jc>// Should fail because input has multiple POJOs.</jc>
214       *    String <jv>json</jv> = <js>"{foo:'bar'}{baz:'qux'}"</js>;
215       *    MyBean <jv>myBean</jv> =<jv>parser</jv>.read(<jv>json</jv>, MyBean.<jk>class</jk>);
216       * </p>
217       *
218       * <p>
219       * <b>Token streams:</b> this setting is not honored by {@link #readTokens(Object) readTokens}
220       * &mdash; the cursor leaves end-of-input checking to the caller.
221       *
222       * @return This object.
223       */
224      public SELF validateEnd() {
225         return validateEnd(true);
226      }
227
228      /**
229       * Same as {@link #validateEnd()} but allows you to explicitly specify the value.
230       *
231       * @param value The value for this setting.
232       * @return This object.
233       */
234      public SELF validateEnd(boolean value) {
235         validateEnd = value;
236         return self();
237      }
238   }
239
240   /** Default parser, all default settings.*/
241   public static final JsonParser DEFAULT = new JsonParser(create());
242
243   /**
244    * Creates a new builder for this object.
245    *
246    * @return A new builder.
247    */
248   @SuppressWarnings({
249      "java:S1452" // Self-typed builder: Builder<?> is the only non-raw, leaf-free return; chaining + build() unaffected.
250   })
251   public static Builder<?> create() {
252      return new Builder<>();
253   }
254
255   protected final boolean validateEnd;
256
257   private final Map<BeanPropertyMeta,JsonBeanPropertyMeta> jsonBeanPropertyMetas = new ConcurrentHashMap<>();
258   private final Map<ClassMeta<?>,JsonClassMeta> jsonClassMetas = new ConcurrentHashMap<>();
259   
260
261   /**
262    * Constructor.
263    *
264    * @param builder The builder for this object.
265    */
266   public JsonParser(Builder<?> builder) {
267      super(builder);
268      validateEnd = builder.validateEnd;
269   }
270
271   @Override /* Overridden from Context */
272   public Builder<?> copy() {
273      return new Builder<>(this);
274   }
275
276   @Override /* Overridden from Context */
277   public JsonParserSession.Builder<?> createSession() {
278      return JsonParserSession.create(this);
279   }
280
281   @Override /* Overridden from JsonMetaProvider */
282   public JsonBeanPropertyMeta getJsonBeanPropertyMeta(BeanPropertyMeta bpm) {
283      if (bpm == null)
284         return JsonBeanPropertyMeta.DEFAULT;
285      return jsonBeanPropertyMetas.computeIfAbsent(bpm, k -> new JsonBeanPropertyMeta(k.getDelegateFor(), this));
286   }
287
288   @Override /* Overridden from JsonMetaProvider */
289   public JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) {
290      return jsonClassMetas.computeIfAbsent(cm, k -> new JsonClassMeta(k, this));
291   }
292
293   @Override /* Overridden from Context */
294   public JsonParserSession getSession() { return createSession().build(); }
295
296   /**
297    * Convenience delegator that opens a {@link JsonTokenReader} over the input using
298    * <b>default session arguments</b> (mirrors {@link #read(Object, Class)}).
299    *
300    * <p>
301    * The real implementation lives on {@link JsonParserSession#readTokens(Object)}.  Callers
302    * that need request-derived configuration (locale, timezone, schema, swaps) should call
303    * {@link #createSession()} and invoke {@link JsonParserSession#readTokens(Object)} on the
304    * built session instead.
305    *
306    * @param input The input.  Accepts {@link Reader}, {@link CharSequence}, {@link InputStream},
307    *    <code><jk>byte</jk>[]</code>, or {@link File}.
308    * @return A new {@link JsonTokenReader}.
309    * @throws IOException If a problem occurred opening the underlying input.
310    */
311   @Override /* TokenReadable */
312   public TokenReader readTokens(Object input) throws IOException {
313      return getSession().readTokens(input);
314   }
315
316   /**
317    * Validate end.
318    *
319    * @see Builder#validateEnd()
320    * @return
321    *    <jk>true</jk> if after parsing a POJO from the input, verifies that the remaining input in
322    *    the stream consists of only comments or whitespace.
323    */
324   protected final boolean isValidateEnd() { return validateEnd; }
325
326   /**
327    * Convenience delegator for the streaming array-element {@link RecordReader} (uses default
328    * session args; see {@link #readTokens(Object)}).  Real impl on
329    * {@link JsonParserSession#readArrayRecords(Object)}.
330    *
331    * @param input The input.
332    * @return A new element-streamed {@link RecordReader}.
333    * @throws IOException If a problem occurred opening the underlying input.
334    */
335   @Override /* ArrayRecordReadable */
336   public RecordReader readArrayRecords(Object input) throws IOException {
337      return getSession().readArrayRecords(input);
338   }
339}